"tokenize" --- Tokenizador para código-fonte Python
***************************************************

**Código-fonte:** Lib/tokenize.py

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

O módulo "tokenize" fornece um scanner léxico para código-fonte
Python, implementado em Python. O scanner neste módulo retorna
comentários como tokens também, tornando-o útil para implementar
"pretty-printers", incluindo colorizadores para exibições na tela.

Para simplificar o tratamento do fluxo de tokens, todos os tokens
operadores e delimitadores e "Ellipsis" são retornados usando o tipo
de token genérico "OP". O tipo exato pode ser determinado verificando
a propriedade "exact_type" na *tupla nomeada* retornada de
"tokenize.tokenize()".

Aviso:

  Observe que as funções neste módulo são projetadas apenas para
  analisar código Python sintaticamente válido (código que não levanta
  exceção quando analisado usando "ast.parse()"). O comportamento das
  funções neste módulo é **indefinido** ao fornecer código Python
  inválido e pode mudar a qualquer momento.


Tokenizando entradas
====================

O ponto de entrada principal é um *gerador*:

tokenize.tokenize(readline)

   O gerador "tokenize()" requer um argumento, *readline*, que deve
   ser um objeto chamável que fornece a mesma interface que o método
   "io.IOBase.readline()" de objetos arquivo. Cada chamada para a
   função deve retornar uma linha de entrada como bytes.

   O gerador produz tuplas de 5 elementos com estes membros: o tipo de
   token; a string de token; uma tupla de 2 elementos "(srow, scol)"
   de ints especificando a linha e a coluna onde o token começa na
   fonte; uma tupla de 2 elementos "(erow, ecol)" de ints
   especificando a linha e a coluna onde o token termina na fonte; e a
   linha na qual o token foi encontrado. A linha passada (o último
   item da tupla) é a linha *física*. A tupla 5 elementos é retornada
   como uma *tupla nomeada* com os nomes dos campos: "tipo string
   início fim linha".

   A *tupla nomeada* retornada tem uma propriedade adicional chamada
   "exact_type" que contém o tipo exato do operador para tokens "OP".
   Para todos os outros tipos de token, "exact_type" é igual ao campo
   "type" da tupla nomeada.

   Alterado na versão 3.1: Adiciona suporte para tuplas nomeadas.

   Alterado na versão 3.3: Adicionado suporte para "exact_type".

   "tokenize()" determina a codificação de origem do arquivo
   procurando por um BOM UTF-8 ou cookie de codificação, de acordo com
   **PEP 263**.

tokenize.generate_tokens(readline)

   Tokeniza uma fonte lendo strings unicode em vez de bytes.

   Assim como "tokenize()", o argumento *readline* é um chamável que
   retorna uma única linha de entrada. No entanto, "generate_tokens()"
   espera que *readline* retorne um objeto str em vez de bytes.

   O resultado é um iterador produzindo tuplas nomeadas, exatamente
   como "tokenize()". Ele não produz um token "ENCODING".

Todas as constantes do módulo "token" também são exportadas de
"tokenize".

Outra função é fornecida para reverter o processo de tokenização. Isso
é útil para criar ferramentas que tokenizam um script, modificam o
fluxo de tokens e escrevem de volta o script modificado.

tokenize.untokenize(iterable)

   Converte tokens de volta para o código-fonte Python. O *iterable*
   deve retornar sequências com pelo menos dois elementos, o tipo de
   token e a string do token. Quaisquer elementos de sequência
   adicionais são ignorados.

   O resultado é garantido para tokenizar de volta para corresponder à
   entrada, de modo que a conversão seja sem perdas e as viagens de
   ida e volta sejam garantidas. A garantia se aplica somente ao tipo
   de token e à sequência de tokens, pois o espaçamento entre os
   tokens (posições de coluna) pode mudar.

   Retorna bytes, codificados usando o token "ENCODING", que é a
   primeira sequência de tokens gerada por "tokenize()". Se não houver
   nenhum token de codificação na entrada, ele retorna um str em vez
   disso.

"tokenize()" precisa detectar a codificação dos arquivos fonte que ele
tokeniza. A função que ele usa para fazer isso está disponível:

tokenize.detect_encoding(readline)

   A função "detect_encoding()" é usada para detectar a codificação
   que deve ser usada para decodificar um arquivo de origem Python.
   Ela requer um argumento, readline, da mesma forma que o gerador
   "tokenize()".

   Ele chamará readline no máximo duas vezes e retornará a codificação
   usada (como uma string) e uma lista de todas as linhas (não
   decodificadas de bytes) que ele leu.

   Ele detecta a codificação a partir da presença de um BOM UTF-8 ou
   um cookie de codificação conforme especificado em **PEP 263**. Se
   um BOM e um cookie estiverem presentes, mas discordarem, uma
   exceção "SyntaxError" será levantada. Observe que se o BOM for
   encontrado, "'utf-8-sig'" será retornado como uma codificação.

   Se nenhuma codificação for especificada, o padrão "'utf-8'" será
   retornado.

   Use "open()" para abrir arquivos de código-fonte Python: ele usa
   "detect_encoding()" para detectar a codificação do arquivo.

tokenize.open(filename)

   Abre um arquivo no modo somente leitura usando a codificação
   detectada por "detect_encoding()".

   Adicionado na versão 3.2.

exception tokenize.TokenError

   Levantada quando uma docstring ou expressão que pode ser dividida
   em várias linhas não é concluída em nenhum lugar do arquivo, por
   exemplo:

      """Início da
      docstring

   ou:

      [1,
       2,
       3


Uso na linha de comando
=======================

Adicionado na versão 3.3.

O módulo "tokenize" pode ser executado como um script a partir da
linha de comando. É tão simples quanto:

   python -m tokenize [-e] [nome-do-arquivo.py]

As seguintes opções são aceitas:

-h, --help

   mostra esta mensagem de ajuda e sai

-e, --exact

   exibe nomes de tokens usando o tipo exato

Se "nome-de-arquivo.py" for especificado, seu conteúdo será tokenizado
para stdout. Caso contrário, a tokenização será realizada em stdin.


Exemplos
========

Exemplo de um reescritor de script que transforma literais float em
objetos Decimal:

   from tokenize import tokenize, untokenize, NUMBER, STRING, NAME, OP
   from io import BytesIO

   def decistmt(s):
       """Substitui Decimals por floats em uma string de instruções.

       >>> from decimal import Decimal
       >>> s = 'print(+21.3e-5*-.1234/81.7)'
       >>> decistmt(s)
       "print (+Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7'))"

       O formato do expoente é herdado da biblioteca da plataforma C. Casos
       conhecidos são "e-007" (Windows) e "e-07" (não Windows). Como estamos
       mostrando apenas 12 dígitos, e o 13º não está próximo de 5, o restante
       da saída deve ser independente da plataforma.

       >>> exec(s)  #doctest: +ELLIPSIS
       -3.21716034272e-0...7

       A saída dos cálculos com Decimal deve ser idêntica em todas as
       plataformas.

       >>> exec(decistmt(s))
       -3.217160342717258261933904529E-7
       """
       result = []
       g = tokenize(BytesIO(s.encode('utf-8')).readline)  # tokenize the string
       for toknum, tokval, _, _, _ in g:
           if toknum == NUMBER and '.' in tokval:  # replace NUMBER tokens
               result.extend([
                   (NAME, 'Decimal'),
                   (OP, '('),
                   (STRING, repr(tokval)),
                   (OP, ')')
               ])
           else:
               result.append((toknum, tokval))
       return untokenize(result).decode('utf-8')

Exemplo de tokenização a partir da linha de comando. O script:

   def say_hello():
       print("Hello, World!")

   say_hello()

será tokenizado para a seguinte saída, onde a primeira coluna é o
intervalo das coordenadas da linha/coluna onde o token é encontrado, a
segunda coluna é o nome do token e a coluna final é o valor do token
(se houver)

   $ python -m tokenize hello.py
   0,0-0,0:            ENCODING       'utf-8'
   1,0-1,3:            NAME           'def'
   1,4-1,13:           NAME           'say_hello'
   1,13-1,14:          OP             '('
   1,14-1,15:          OP             ')'
   1,15-1,16:          OP             ':'
   1,16-1,17:          NEWLINE        '\n'
   2,0-2,4:            INDENT         '    '
   2,4-2,9:            NAME           'print'
   2,9-2,10:           OP             '('
   2,10-2,25:          STRING         '"Hello, World!"'
   2,25-2,26:          OP             ')'
   2,26-2,27:          NEWLINE        '\n'
   3,0-3,1:            NL             '\n'
   4,0-4,0:            DEDENT         ''
   4,0-4,9:            NAME           'say_hello'
   4,9-4,10:           OP             '('
   4,10-4,11:          OP             ')'
   4,11-4,12:          NEWLINE        '\n'
   5,0-5,0:            ENDMARKER      ''

Os nomes exatos dos tipos de token podem ser exibidos usando a opção
"-e":

   $ python -m tokenize -e hello.py
   0,0-0,0:            ENCODING       'utf-8'
   1,0-1,3:            NAME           'def'
   1,4-1,13:           NAME           'say_hello'
   1,13-1,14:          LPAR           '('
   1,14-1,15:          RPAR           ')'
   1,15-1,16:          COLON          ':'
   1,16-1,17:          NEWLINE        '\n'
   2,0-2,4:            INDENT         '    '
   2,4-2,9:            NAME           'print'
   2,9-2,10:           LPAR           '('
   2,10-2,25:          STRING         '"Hello, World!"'
   2,25-2,26:          RPAR           ')'
   2,26-2,27:          NEWLINE        '\n'
   3,0-3,1:            NL             '\n'
   4,0-4,0:            DEDENT         ''
   4,0-4,9:            NAME           'say_hello'
   4,9-4,10:           LPAR           '('
   4,10-4,11:          RPAR           ')'
   4,11-4,12:          NEWLINE        '\n'
   5,0-5,0:            ENDMARKER      ''

Exemplo de tokenização de um arquivo programaticamente, lendo strings
unicode em vez de bytes com "generate_tokens()":

   import tokenize

   with tokenize.open('hello.py') as f:
       tokens = tokenize.generate_tokens(f.readline)
       for token in tokens:
           print(token)

Ou lendo bytes diretamente com "tokenize()":

   import tokenize

   with open('hello.py', 'rb') as f:
       tokens = tokenize.tokenize(f.readline)
       for token in tokens:
           print(token)
