
``tokenize`` --- Tokenizer for Python source
********************************************

**Source code:** Lib/tokenize.py

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

The ``tokenize`` module provides a lexical scanner for Python source
code, implemented in Python.  The scanner in this module returns
comments as tokens as well, making it useful for implementing "pretty-
printers," including colorizers for on-screen displays.

To simplify token stream handling, all *Operators* and *Delimiters*
tokens are returned using the generic ``token.OP`` token type.  The
exact type can be determined by checking the token ``string`` field on
the *named tuple* returned from ``tokenize.tokenize()`` for the
character sequence that identifies a specific operator token.

The primary entry point is a *generator*:

tokenize.tokenize(readline)

   The ``tokenize()`` generator requires one argument, *readline*,
   which must be a callable object which provides the same interface
   as the ``io.IOBase.readline()`` method of file objects.  Each call
   to the function should return one line of input as bytes.

   The generator produces 5-tuples with these members: the token type;
   the token string; a 2-tuple ``(srow, scol)`` of ints specifying the
   row and column where the token begins in the source; a 2-tuple
   ``(erow, ecol)`` of ints specifying the row and column where the
   token ends in the source; and the line on which the token was
   found. The line passed (the last tuple item) is the *logical* line;
   continuation lines are included.  The 5 tuple is returned as a
   *named tuple* with the field names: ``type string start end line``.

   Changed in version 3.1: Added support for named tuples.

   ``tokenize()`` determines the source encoding of the file by
   looking for a UTF-8 BOM or encoding cookie, according to **PEP
   263**.

All constants from the ``token`` module are also exported from
``tokenize``, as are three additional token type values:

tokenize.COMMENT

   Token value used to indicate a comment.

tokenize.NL

   Token value used to indicate a non-terminating newline.  The
   NEWLINE token indicates the end of a logical line of Python code;
   NL tokens are generated when a logical line of code is continued
   over multiple physical lines.

tokenize.ENCODING

   Token value that indicates the encoding used to decode the source
   bytes into text. The first token returned by ``tokenize()`` will
   always be an ENCODING token.

Another function is provided to reverse the tokenization process. This
is useful for creating tools that tokenize a script, modify the token
stream, and write back the modified script.

tokenize.untokenize(iterable)

   Converts tokens back into Python source code.  The *iterable* must
   return sequences with at least two elements, the token type and the
   token string. Any additional sequence elements are ignored.

   The reconstructed script is returned as a single string.  The
   result is guaranteed to tokenize back to match the input so that
   the conversion is lossless and round-trips are assured.  The
   guarantee applies only to the token type and token string as the
   spacing between tokens (column positions) may change.

   It returns bytes, encoded using the ENCODING token, which is the
   first token sequence output by ``tokenize()``.

``tokenize()`` needs to detect the encoding of source files it
tokenizes. The function it uses to do this is available:

tokenize.detect_encoding(readline)

   The ``detect_encoding()`` function is used to detect the encoding
   that should be used to decode a Python source file. It requires one
   argument, readline, in the same way as the ``tokenize()``
   generator.

   It will call readline a maximum of twice, and return the encoding
   used (as a string) and a list of any lines (not decoded from bytes)
   it has read in.

   It detects the encoding from the presence of a UTF-8 BOM or an
   encoding cookie as specified in **PEP 263**. If both a BOM and a
   cookie are present, but disagree, a SyntaxError will be raised.
   Note that if the BOM is found, ``'utf-8-sig'`` will be returned as
   an encoding.

   If no encoding is specified, then the default of ``'utf-8'`` will
   be returned.

   Use ``open()`` to open Python source files: it uses
   ``detect_encoding()`` to detect the file encoding.

tokenize.open(filename)

   Open a file in read only mode using the encoding detected by
   ``detect_encoding()``.

   New in version 3.2.

Example of a script rewriter that transforms float literals into
Decimal objects:

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

   def decistmt(s):
       """Substitute Decimals for floats in a string of statements.

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

       The format of the exponent is inherited from the platform C library.
       Known cases are "e-007" (Windows) and "e-07" (not Windows).  Since
       we're only showing 12 digits, and the 13th isn't close to 5, the
       rest of the output should be platform-independent.

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

       Output from calculations with Decimal should be identical across all
       platforms.

       >>> 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')
