class_docstr: This is the central parsing class Jinja uses.  It's passed to
  extensions and can be used to parse expressions or statements.
class_docstr_tok: ["This","is","the","central","parsing","class","Jinja","uses",".","It","'s","passed","to","extensions","and","can","be","used","to","parse","expressions","or","statements","."]
docstr: Works like `parse_expression` but if multiple expressions are
  delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
  This method could also return a regular expression instead of a tuple
  if no commas where found.
  
  The default parsing mode is a full tuple.  If `simplified` is `True`
  only names and literals are parsed.  The `no_condexpr` parameter is
  forwarded to :meth:`parse_expression`.
  
  Because tuples do not require delimiters and may end in a bogus comma
  an extra hint is needed that marks the end of a tuple.  For example
  for loops support tuples between `for` and `in`.  In that case the
  `extra_end_rules` is set to ``['name:in']``.
  
  `explicit_parentheses` is true if the parsing was triggered by an
  expression in parentheses.  This is used to figure out if an empty
  tuple is a valid expression or not.
code: def parse_tuple(
      self,
      simplified: bool = False,
      with_condexpr: bool = True,
      extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
      explicit_parentheses: bool = False,
  ) -> t.Union[nodes.Tuple, nodes.Expr]:
      """Works like `parse_expression` but if multiple expressions are
      delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
      This method could also return a regular expression instead of a tuple
      if no commas where found.
  
      The default parsing mode is a full tuple.  If `simplified` is `True`
      only names and literals are parsed.  The `no_condexpr` parameter is
      forwarded to :meth:`parse_expression`.
  
      Because tuples do not require delimiters and may end in a bogus comma
      an extra hint is needed that marks the end of a tuple.  For example
      for loops support tuples between `for` and `in`.  In that case the
      `extra_end_rules` is set to ``['name:in']``.
  
      `explicit_parentheses` is true if the parsing was triggered by an
      expression in parentheses.  This is used to figure out if an empty
      tuple is a valid expression or not.
      """
      lineno = self.stream.current.lineno
      if simplified:
          parse = self.parse_primary
      elif with_condexpr:
          parse = self.parse_expression
      else:
  
          def parse() -> nodes.Expr:
              return self.parse_expression(with_condexpr=False)
  
      args: t.List[nodes.Expr] = []
      is_tuple = False
  
      while True:
          if args:
              self.stream.expect("comma")
          if self.is_tuple_end(extra_end_rules):
              break
          args.append(parse())
          if self.stream.current.type == "comma":
              is_tuple = True
          else:
              break
          lineno = self.stream.current.lineno
  
      if not is_tuple:
          if args:
              return args[0]
  
          # if we don't have explicit parentheses, an empty tuple is
          # not a valid expression.  This would mean nothing (literally
          # nothing) in the spot of an expression would be an empty
          # tuple.
          if not explicit_parentheses:
              self.fail(
                  "Expected an expression,"
                  f" got {describe_token(self.stream.current)!r}"
              )
  
      return nodes.Tuple(args, "load", lineno=lineno)
  
imports: import typing
  import typing
  from .None import nodes
  from .exceptions import TemplateAssertionError
  from .exceptions import TemplateSyntaxError
  from .lexer import describe_token
  from .lexer import describe_token_expr
label_desc: Use image node_id 41 for calling the Parser obj's underlying member method code with example usage: obj.parse_tuple(simplified, with_condexpr, extra_end_rules, explicit_parentheses) and returns: nodes, args, self