| :mod:`tokenize` --- Tokenizer for Python source |
| =============================================== |
| |
| .. module:: tokenize |
| :synopsis: Lexical scanner for Python source code. |
| .. moduleauthor:: Ka Ping Yee |
| .. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org> |
| |
| |
| The :mod:`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. |
| |
| The primary entry point is a :term:`generator`: |
| |
| .. function:: tokenize(readline) |
| |
| The :func:`tokenize` generator requires one argument, *readline*, which |
| must be a callable object which provides the same interface as the |
| :meth:`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 :term:`named tuple` with the field names: |
| ``type string start end line``. |
| |
| .. versionchanged:: 3.1 |
| Added support for named tuples. |
| |
| :func:`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 :mod:`token` module are also exported from |
| :mod:`tokenize`, as are three additional token type values: |
| |
| .. data:: COMMENT |
| |
| Token value used to indicate a comment. |
| |
| |
| .. data:: 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. |
| |
| |
| .. data:: ENCODING |
| |
| Token value that indicates the encoding used to decode the source bytes |
| into text. The first token returned by :func:`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. |
| |
| |
| .. function:: 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 :func:`tokenize`. |
| |
| |
| :func:`tokenize` needs to detect the encoding of source files it tokenizes. The |
| function it uses to do this is available: |
| |
| .. function:: detect_encoding(readline) |
| |
| The :func:`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 :func:`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. |
| |
| If no encoding is specified, then the default of ``'utf-8'`` will be returned. |
| |
| |
| Example of a script re-writer 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') |
| |
| |