[Python-checkins] peps: PEP 511: add the text of the PEP

Terry Reedy tjreedy at udel.edu
Tue Jan 12 22:14:47 EST 2016


On 1/12/2016 7:26 PM, victor.stinner wrote:

>    PEP 511: add the text of the PEP

>   Abstract
>   ========
>
> -Propose an API to support AST transformers.
> +Propose an API to support AST transformers. Add also ``-o OPTIM_TAG``
> +command line option to change ``.pyc`` filenames. Raise an
> +``ImportError`` exception on import if the ``.pyc`` file is missing and
> +the AST transformers required to transform the code are missing.

> +AST transformers are not needed code transformed ahead of time (loaded
> +from ``.pyc`` files).

This sentence is garbled.

> +Transforming the code allows to extend the Python language for specific
> +use cases. Transforming an Abstract Syntax Tree (AST) is a convenient
> +way to implement an optimizer. It's easier to work on the AST than
> +working on the bytecode, AST contains more information and is more high
> +level.

For many things, it should also be easier to work on the AST than the 
source code.  But, it would be nice to have an AST tree pattern matcher, 
with capture groups, equivalent to re for linear text.

> +This PEP proposes to add an API to register AST transformers.
> +
> +A new ``-o OPTIM_TAG`` command line option is added to only load
> +transformed code: it changes the name of searched ``.pyc`` files. If the
> +``.pyc`` file of a module is missing and the ``.py`` is available, an
> +``ImportError`` exception is raised import if the AST transformers

'raised on import'

> +required to transform the code are missing. The import behaviour with
> +the default optimizer tag (``'opt'``) is unchanged.
> +
> +The transformation can done ahead of time.

I presume you mean during the one-time compile and generate .pyc step.

 > It allows to implement powerful but expensive transformations.

For many transformations, the expensive part is finding subtrees 
matching the applicable pattern.

The Windows installer optionally runs compileall.  Another minute for an 
install would not be too bad.  In any case, stdlib modules are stable 
for months at a time.  Ditto for installations of most 3rd party 
packages. Getting months of use from one time costs, added on to 
installs that may proceed while one does something else, is an important 
point.

> +Use Cases
> +=========
> +
> +This section give examples of use cases explaining when and how AST
> +transformers will be used.
> +
> +Interactive interpreter
> +-----------------------
> +
> +It will be possible to use AST transformers with the interactive
> +interpreter which is popular in Python and commonly used to demonstrate
> +Python.

Possible, but limited to default inexpensive transformations with 
immediate payoff, such as the current peephole optimizer.

> +The code is transformed at runtime and so the interpreter can be slower
> +when expensive AST transformers are used.

Expensive transformers should be turned off.  I am not sure what you are 
saying here.

Now for some possible dumb quesitons.

> +Build a transformed package
> +---------------------------

I am probably missing some the import differences between this and

+Install a package containing transformed .pyc files
+---------------------------------------------------

and

+Build .pyc files when installing a package
+------------------------------------------

> +It will be possible to build a package of the transformed code.
> +
> +A transformer can have a configuration. The configuration is not stored
> +in the package.
> +
> +All ``.pyc`` files of the package must be transformed with the same AST
> +transformers and the same transformers configuration.

Why? is unclear to me.  The issues I have:

Suppose I write (as I might) one or more recursion-to-iteration 
transformers (within one transformer module).  Each function 
transformation would be independent of all others, so could potentially 
be applied on a function-to-function basis.  (For instance, decorators 
might be used to indicate which transformer, if any, to apply to a 
particular function.) For simple linear recursive functions (such as 
factorial), eliminating the repeated function calls might double the speed.

The grouping of modules into packages is somewhat arbitrary.  An 
application often uses modules from multiple packages, so it must anyway 
execute with different modules having different optimizations.

A transform may not be 100% reliable, or may not be believed to be so by 
the programmer, or may depend on information supplies by the programmer. 
  So a careful programmer only wants it applied after testing.  The 
boundaries of what has been tested may not coincide with package boundaries.

A related issue is that AST transformations may affect tracebacks, and a 
programmer might want to temporarily disable a transformation for one 
function, without having every module in a large package re-compiled to 
yet another set of .pyc files.  I am partly worried here about 
combinatorial explosion of space usage.

Suppose a transformer looks for certain decorators.  Running that 
transformer over files that do not contain the trigger decorators is 
harmless, in that nothing will be changed, but is also irrelevant and a 
waste of time.

> +API to support AST transformers:

> +* Add ``sys.ast_transformers``: list of AST transformers used to rewrite
> +  an AST tree. The list is empty by default: no AST transformer.

I do not understand how this would work, or rather it seems to conflict 
with 'all modules in each package must have a matching set of optimized 
.pycs'.

> +* Add ``sys.implementation.ast_transformers``: name of AST
> +  transformers registered in ``sys.ast_transformers``

How is this different from sys.ast_transformers?

...

> +AST transformer
> +----------------
> +
> +Scary AST transformer replacing all strings with ``"Ni! Ni! Ni!"``::

This helps a lot.

> +    import ast
> +    import sys
> +
> +
> +    class KnightsWhoSayNi(ast.NodeTransformer):
> +        def visit_Str(self, node):
> +            node.s = 'Ni! Ni! Ni!'
> +            return node

This I can do today.  Tree pattern recognition has to be hard-coded and 
substring capture done manually.

> +    class ASTTransformer:
> +        name = "knights_who_say_ni"
> +
> +        def __call__(self, tree, context):
> +            KnightsWhoSayNi().visit(tree)
> +            return tree
> +
> +
> +    # register the AST transformer
> +    sys.ast_transformers.append(ASTTransformer())

This is new, with the result

> +    # execute code which will be transformed by ast_transformer()
> +    exec("print('Hello World!')")
> +
> +Output::
> +
> +    Ni! Ni! Ni!

that this happens automatically, without having to write out
    exec(compile(Transformer.visit(compile-to-ast(code))))
More important, the transformation happens automatically for import 
statements without having to split up the import process to dig out and 
similarly augment the compile process.  That will

tjr



More information about the Python-checkins mailing list