"ast" --- Árboles de sintaxis abstracta
***************************************

**Código fuente:** Lib/ast.py

======================================================================

El módulo "ast" ayuda a las aplicaciones de Python a procesar árboles
de la gramática de sintaxis abstracta de Python. La sintaxis abstracta
en sí misma puede cambiar con cada versión de Python; Este módulo
ayuda a descubrir mediante programación cómo se ve la gramática
actual.

Se puede generar un árbol de sintaxis abstracta pasando
"ast.PyCF_ONLY_AST" como un indicador de la función incorporada
"compile()", o usando el ayudante "parse()" provisto en este módulo.
El resultado será un árbol de objetos cuyas clases todas heredan de
"ast.AST". Se puede compilar un árbol de sintaxis abstracta en un
objeto de código Python utilizando la función incorporada "compile()".


Clases Nodo
===========

class ast.AST

   Esta es la base de todas las clases de nodo AST. Las clases de nodo
   reales se derivan del archivo "Parser/Python.asdl", que se
   reproduce abajo. Se definen en el módulo "_ast" C y se reexportan
   en "ast".

   Hay una clase definida para cada símbolo del lado izquierdo en la
   gramática abstracta (por ejemplo, "ast.stmt" o "ast.expr"). Además,
   hay una clase definida para cada constructor en el lado derecho;
   estas clases heredan de las clases para los árboles del lado
   izquierdo. Por ejemplo, "ast.BinOp" hereda de "ast.expr". Para las
   reglas de producción con alternativas (también conocidas como
   "sumas"), la clase del lado izquierdo es abstracta: solo se crean
   instancias de nodos de constructor específicos.

   _fields

      Cada clase concreta tiene un atributo "_fields" que proporciona
      los nombres de todos los nodos secundarios.

      Cada instancia de una clase concreta tiene un atributo para cada
      nodo secundario, del tipo definido en la gramática. Por ejemplo,
      las instancias "ast.BinOp" tienen un atributo "left" de tipo
      "ast.expr".

      Si estos atributos están marcados como opcionales en la
      gramática (usando un signo de interrogación), el valor podría
      ser "None". Si los atributos pueden tener cero o más valores
      (marcados con un asterisco), los valores se representan como
      listas de Python. Todos los atributos posibles deben estar
      presentes y tener valores válidos al compilar un AST con
      "compile()".

   lineno
   col_offset
   end_lineno
   end_col_offset

      Las instancias de las subclases "ast.expr" y "ast.stmt" tienen
      atributos "lineno", "col_offset", "lineno", y "col_offset". Los
      "lineno" y "end_lineno" son los números de la primera y última
      línea del intervalo de texto de origen (1 indexado, por lo que
      la primera línea es la línea 1) y el "col_offset" y
      "end_col_offset" son las correspondientes compensaciones de
      bytes UTF-8 del primer y último token que generó el nodo. El
      desplazamiento UTF-8 se registra porque el analizador utiliza
      UTF-8 internamente.

      Tenga en cuenta que el compilador no requiere las posiciones
      finales y, por lo tanto, son opcionales. El desplazamiento final
      es *después* del último símbolo, por ejemplo, uno puede obtener
      el segmento fuente de un nodo de expresión de una línea usando
      "source_line[node.col_offset: node.end_col_offset]".

   El constructor de una clase "ast.T" analiza sus argumentos de la
   siguiente manera:

   * Si hay argumentos posicionales, debe haber tantos como elementos
     en "T._fields"; serán asignados como atributos de estos nombres.

   * Si hay argumentos de palabras clave, establecerán los atributos
     de los mismos nombres a los valores dados.

   Por ejemplo, para crear y completar un nodo "ast.UnaryOp", puede
   usar

      node = ast.UnaryOp()
      node.op = ast.USub()
      node.operand = ast.Constant()
      node.operand.value = 5
      node.operand.lineno = 0
      node.operand.col_offset = 0
      node.lineno = 0
      node.col_offset = 0

   o la más compacta

      node = ast.UnaryOp(ast.USub(), ast.Constant(5, lineno=0, col_offset=0),
                         lineno=0, col_offset=0)

Distinto en la versión 3.8: La clase "ast.Constant" ahora se usa para
todas las constantes.

Obsoleto desde la versión 3.8: Las clases antiguas "ast.Num",
"ast.Str", "ast.Bytes", "ast.NameConstant" y "ast.Ellipsis" todavía
están disponibles, pero se eliminarán en futuras versiones de Python.
Mientras tanto, instanciarlos retornará una instancia de una clase
diferente.


Gramática abstracta
===================

La gramática abstracta se define actualmente de la siguiente manera:

   -- ASDL's 5 builtin types are:
   -- identifier, int, string, object, constant

   module Python
   {
       mod = Module(stmt* body, type_ignore *type_ignores)
           | Interactive(stmt* body)
           | Expression(expr body)
           | FunctionType(expr* argtypes, expr returns)

           -- not really an actual node but useful in Jython's typesystem.
           | Suite(stmt* body)

       stmt = FunctionDef(identifier name, arguments args,
                          stmt* body, expr* decorator_list, expr? returns,
                          string? type_comment)
             | AsyncFunctionDef(identifier name, arguments args,
                                stmt* body, expr* decorator_list, expr? returns,
                                string? type_comment)

             | ClassDef(identifier name,
                expr* bases,
                keyword* keywords,
                stmt* body,
                expr* decorator_list)
             | Return(expr? value)

             | Delete(expr* targets)
             | Assign(expr* targets, expr value, string? type_comment)
             | AugAssign(expr target, operator op, expr value)
             -- 'simple' indicates that we annotate simple name without parens
             | AnnAssign(expr target, expr annotation, expr? value, int simple)

             -- use 'orelse' because else is a keyword in target languages
             | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
             | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)
             | While(expr test, stmt* body, stmt* orelse)
             | If(expr test, stmt* body, stmt* orelse)
             | With(withitem* items, stmt* body, string? type_comment)
             | AsyncWith(withitem* items, stmt* body, string? type_comment)

             | Raise(expr? exc, expr? cause)
             | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
             | Assert(expr test, expr? msg)

             | Import(alias* names)
             | ImportFrom(identifier? module, alias* names, int? level)

             | Global(identifier* names)
             | Nonlocal(identifier* names)
             | Expr(expr value)
             | Pass | Break | Continue

             -- XXX Jython will be different
             -- col_offset is the byte offset in the utf8 string the parser uses
             attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

             -- BoolOp() can use left & right?
       expr = BoolOp(boolop op, expr* values)
            | NamedExpr(expr target, expr value)
            | BinOp(expr left, operator op, expr right)
            | UnaryOp(unaryop op, expr operand)
            | Lambda(arguments args, expr body)
            | IfExp(expr test, expr body, expr orelse)
            | Dict(expr* keys, expr* values)
            | Set(expr* elts)
            | ListComp(expr elt, comprehension* generators)
            | SetComp(expr elt, comprehension* generators)
            | DictComp(expr key, expr value, comprehension* generators)
            | GeneratorExp(expr elt, comprehension* generators)
            -- the grammar constrains where yield expressions can occur
            | Await(expr value)
            | Yield(expr? value)
            | YieldFrom(expr value)
            -- need sequences for compare to distinguish between
            -- x < 4 < 3 and (x < 4) < 3
            | Compare(expr left, cmpop* ops, expr* comparators)
            | Call(expr func, expr* args, keyword* keywords)
            | FormattedValue(expr value, int? conversion, expr? format_spec)
            | JoinedStr(expr* values)
            | Constant(constant value, string? kind)

            -- the following expression can appear in assignment context
            | Attribute(expr value, identifier attr, expr_context ctx)
            | Subscript(expr value, slice slice, expr_context ctx)
            | Starred(expr value, expr_context ctx)
            | Name(identifier id, expr_context ctx)
            | List(expr* elts, expr_context ctx)
            | Tuple(expr* elts, expr_context ctx)

             -- col_offset is the byte offset in the utf8 string the parser uses
             attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

       expr_context = Load | Store | Del | AugLoad | AugStore | Param

       slice = Slice(expr? lower, expr? upper, expr? step)
             | ExtSlice(slice* dims)
             | Index(expr value)

       boolop = And | Or

       operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift
                    | RShift | BitOr | BitXor | BitAnd | FloorDiv

       unaryop = Invert | Not | UAdd | USub

       cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn

       comprehension = (expr target, expr iter, expr* ifs, int is_async)

       excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
                       attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

       arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs,
                    expr* kw_defaults, arg? kwarg, expr* defaults)

       arg = (identifier arg, expr? annotation, string? type_comment)
              attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)

       -- keyword arguments supplied to call (NULL identifier for **kwargs)
       keyword = (identifier? arg, expr value)

       -- import name with optional 'as' alias.
       alias = (identifier name, identifier? asname)

       withitem = (expr context_expr, expr? optional_vars)

       type_ignore = TypeIgnore(int lineno, string tag)
   }


Ayudantes de "ast"
==================

Además de las clases de nodo, el módulo "ast" define estas funciones y
clases de utilidad para atravesar árboles de sintaxis abstracta:

ast.parse(source, filename='<unknown>', mode='exec', *, type_comments=False, feature_version=None)

   Analiza la fuente en un nodo AST. Equivalente a "compile(source,
   filename, mode, ast.PyCF_ONLY_AST)".

   Si se proporciona "type_comments=True", el analizador se modifica
   para verificar y retornar los comentarios de tipo según lo
   especificado por **PEP 484** y **PEP 526**. Esto es equivalente a
   agregar "ast.PyCF_TYPE_COMMENTS" a los flags pasados a "compile()".
   Esto informará errores de sintaxis para comentarios de tipo fuera
   de lugar. Sin este flag, los comentarios de tipo se ignorarán y el
   campo "type_comment" en los nodos AST seleccionados siempre será
   "None". Además, las ubicaciones de los comentarios "# type: ignore"
   se retornarán como el atributo "type_ignores" de "Module" (de lo
   contrario, siempre es una lista vacía).

   Además, si "modo" es "'func_type'", la sintaxis de entrada se
   modifica para corresponder a **PEP 484** "comentarios de tipo de
   firma", por ejemplo "(str, int) -> List[str]".

   Además, establece "feature_version" en una tupla "(major, minor)"
   intentará analizar usando la gramática de esa versión de Python.
   Actualmente "major" debe ser igual a "3". Por ejemplo, establece
   "feature_version=(3, 4)" permitirá el uso de "async" y "await" como
   nombres de variables. La versión más baja admitida es "(3, 4)"; la
   más alto es "sys.version_info[0:2]".

   Advertencia:

     Es posible bloquear el intérprete de Python con una cadena de
     caracteres suficientemente grande/compleja debido a las
     limitaciones de profundidad de pila en el compilador AST de
     Python.

   Distinto en la versión 3.8: Se agregaron "type_comments",
   "mode='func_type'" y "feature_version".

ast.literal_eval(node_or_string)

   Evalúa de forma segura un nodo de expresión o una cadena de
   caracteres que contenga un literal de Python o un visualizador de
   contenedor. La cadena o nodo proporcionado solo puede consistir en
   las siguientes estructuras literales de Python: cadenas de
   caracteres, bytes, números, tuplas, listas, diccionarios,
   conjuntos, booleanos y "None".

   Esto se puede usar para evaluar de forma segura las cadenas de
   caracteres que contienen valores de Python de fuentes no confiables
   sin la necesidad de analizar los valores uno mismo. No es capaz de
   evaluar expresiones complejas arbitrariamente, por ejemplo, que
   involucran operadores o indexación.

   Advertencia:

     Es posible bloquear el intérprete de Python con una cadena de
     caracteres suficientemente grande/compleja debido a las
     limitaciones de profundidad de pila en el compilador AST de
     Python.

   Distinto en la versión 3.2: Ahora permite bytes y establece
   literales.

ast.get_docstring(node, clean=True)

   Retorna la cadena de caracteres de documentación del *node* dado
   (que debe ser un nodo "FunctionDef", "AsyncFunctionDef",
   "ClassDef", o "Module"), o "None" si no tiene docstring. Si *clean*
   es verdadero, limpia la sangría del docstring con
   "inspect.cleandoc()".

   Distinto en la versión 3.5: "AsyncFunctionDef" ahora está
   soportada.

ast.get_source_segment(source, node, *, padded=False)

   Obtenga el segmento de código fuente del *source* que generó
   *node*. Si falta información de ubicación ("lineno", "end_lineno",
   "col_offset", o "end_col_offset"), retorna "None".

   Si *padded* es "True", la primera línea de una declaración de
   varias líneas se rellenará con espacios para que coincidan con su
   posición original.

   Nuevo en la versión 3.8.

ast.fix_missing_locations(node)

   Cuando compila un árbol de nodos con "compile()", el compilador
   espera los atributos "lineno" y "col_offset" para cada nodo que los
   soporta. Es bastante tedioso completar los nodos generados, por lo
   que este ayudante agrega estos atributos de forma recursiva donde
   aún no están establecidos, configurándolos en los valores del nodo
   principal. Funciona de forma recursiva comenzando en *node*.

ast.increment_lineno(node, n=1)

   Incremente el número de línea y el número de línea final de cada
   nodo en el árbol comenzando en *node* por *n*. Esto es útil para
   "mover código" a una ubicación diferente en un archivo.

ast.copy_location(new_node, old_node)

   Copia la ubicación de origen ("lineno", "col_offset", "end_lineno",
   y "end_col_offset") de *old_node* a *new_node* si es posible, y
   retorna *new_node*.

ast.iter_fields(node)

   Produce (*yield*) una tupla de "(fieldname, value)" para cada campo
   en "node._fields" que está presente en *node*.

ast.iter_child_nodes(node)

   Cede todos los nodos secundarios directos de *node*, es decir,
   todos los campos que son nodos y todos los elementos de campos que
   son listas de nodos.

ast.walk(node)

   Recursivamente produce todos los nodos descendientes en el árbol
   comenzando en *node* (incluido *node* en sí mismo), en ningún orden
   especificado. Esto es útil si solo desea modificar los nodos en su
   lugar y no le importa el contexto.

class ast.NodeVisitor

   Una clase base de visitante de nodo que recorre el árbol de
   sintaxis abstracta y llama a una función de visitante para cada
   nodo encontrado. Esta función puede retornar un valor que se
   reenvía mediante el método "visit()".

   Esta clase está destinada a ser subclase, con la subclase agregando
   métodos de visitante.

   visit(node)

      Visita un nodo. La implementación predeterminada llama al método
      llamado "self.visit_*classname*" donde *classname* es el nombre
      de la clase de nodo, o "generic_visit()" si ese método no
      existe.

   generic_visit(node)

      Este visitante llama "visit()" en todos los hijos del nodo.

      Tenga en cuenta que los nodos secundarios de los nodos que
      tienen un método de visitante personalizado no se visitarán a
      menos que el visitante llame "generic_visit()" o los visite a sí
      mismo.

   No use "NodeVisitor" si desea aplicar cambios a los nodos durante
   el recorrido. Para esto existe un visitante especial
   ("NodeTransformer") que permite modificaciones.

   Obsoleto desde la versión 3.8: Los métodos "visit_Num()",
   "visit_Str()", "visit_Bytes()", "visit_NameConstant()" y
   "visit_Ellipsis()" están en desuso ahora y no serán llamados en
   futuras versiones de Python. Agregue el método "visit_Constant()"
   para manejar todos los nodos constantes.

class ast.NodeTransformer

   Una subclase de "NodeVisitor" que recorre el árbol de sintaxis
   abstracta y permite la modificación de nodos.

   La clase "NodeTransformer" recorrerá el AST y usará el valor de
   retorno de los métodos del visitante para reemplazar o eliminar el
   nodo anterior. Si el valor de retorno del método de visitante es
   "None", el nodo se eliminará de su ubicación; de lo contrario, se
   reemplazará con el valor de retorno. El valor de retorno puede ser
   el nodo original, en cuyo caso no se realiza ningún reemplazo.

   Aquí hay un transformador de ejemplo que reescribe todas las
   apariciones de búsquedas de nombres ("foo") en "data['foo']":

      class RewriteName(NodeTransformer):

          def visit_Name(self, node):
              return Subscript(
                  value=Name(id='data', ctx=Load()),
                  slice=Index(value=Constant(value=node.id)),
                  ctx=node.ctx
              )

   Tenga en cuenta que si el nodo en el que está operando tiene nodos
   secundarios, debe transformar los nodos secundarios usted mismo o
   llamar primero al método "generic_visit()" para el nodo.

   Para los nodos que formaban parte de una colección de declaraciones
   (que se aplica a todos los nodos de declaración), el visitante
   también puede retornar una lista de nodos en lugar de solo un nodo.

   Si "NodeTransformer" introduce nuevos nodos (que no eran parte del
   árbol original) sin darles información de ubicación (como
   "lineno"), "fix_missing_locations()" debería llamarse con el nuevo
   sub-árbol para recalcular la información de ubicación

      tree = ast.parse('foo', mode='eval')
      new_tree = fix_missing_locations(RewriteName().visit(tree))

   Usualmente usas el transformador así:

      node = YourTransformer().visit(node)

ast.dump(node, annotate_fields=True, include_attributes=False)

   Retorna un volcado formateado del árbol en *node*. Esto es
   principalmente útil para propósitos de depuración. Si
   *annotate_fields* es verdadero (por defecto), la cadena de
   caracteres retornada mostrará los nombres y los valores de los
   campos. Si *annotate_fields* es falso, la cadena de resultados será
   más compacta omitiendo nombres de campo no ambiguos. Los atributos
   como los números de línea y las compensaciones de columna no se
   vuelcan de forma predeterminada. Si esto se desea,
   *include_attributes* se puede establecer en verdadero.

Ver también:

  Green Tree Snakes, un recurso de documentación externo, tiene buenos
  detalles sobre cómo trabajar con Python AST.

  ASTTokens annotates Python ASTs with the positions of tokens and
  text in the source code that generated them. This is helpful for
  tools that make source code transformations.

  leoAst.py unifies the token-based and parse-tree-based views of
  python programs by inserting two-way links between tokens and ast
  nodes.

  LibCST parses code as a Concrete Syntax Tree that looks like an ast
  tree and keeps all formatting details. It's useful for building
  automated refactoring (codemod) applications and linters.

  Parso is a Python parser that supports error recovery and round-trip
  parsing for different Python versions (in multiple Python versions).
  Parso is also able to list multiple syntax errors in your python
  file.
