Home

Awesome

mcpy

A small and compact Python 3 library to enable syntactic macros at importing time strongly inspired by macropy.

Install

Install from PyPI:

# pip install mcpy

Using macros

Due to mcpy macro extension procedure, you need to enable mcpy before importing the modules using macros and in a separated file. The following 3 file setup works fine for most of the cases:

# run.py
import mcpy.activate
import application

# mymacros.py with your macros definitions
def echo(expr, **kw):
  print('Echo')
  return expr

# application.py 
from mymacros import macros, echo
echo[6*7]

Syntax

mcpy macros can be used in three forms following macropy syntax:

# block form
with macro:
  ...

# expression form
macro[...]

# decorator form
@macro
...

For each case, the macro will receive ... as input and will replace the invokation with the expanded content. Expansion occurs first for outermost nodes. I.e, from outside to inside.

Importing macros

Macros are simple functions. To use functions from a module as macros, use:

from module import macros, ...

Replacing ... with the macros you want to use. Importing all via * won't work. You must declare the macros you want explicitely. mcpy prevents you from accidentally using macros as functions in your code by transforming that import into:

import module

If you want to use some of your macros as regular functions, simply use:

from module import ...

Or use fully qualified names for them:

module.macroname

If the name of a macro conflicts with a name you can provide an alias for the macro:

from module import macros, macroname as alias

Writing macros

No special imports are needed to write your own macros. Just read the documentation for the AST module and consider a macro as a function accepting an AST tree and returning another AST.

def macro(tree, **): return tree

The tree parameter is the only positional parameter the macro is called with. Remaining parameters are called by name and includes a set of useful functionality.

In addittion to a node, you can return None to remove the node, or a list of AST nodes. The expanded macros are recursively expanded until no new macros are found.

from ast import *
def log(expr, to_source, **kw):
    '''Replaces log[expr] with print('expr: ', expr)'''
    label = to_source(expr) + ': '
    return Call(func=Name(id='print', ctx=Load()),
                args=[Str(s=label), expr], keywords=[], starargs=None,
                kwargs=None)

Distinguish how the macro is called

A macro can be called in three different ways. The way a macro is called is recorded in the syntax named parameter (one of 'block', 'expr' or 'decorator') so you can distinguish the syntax used in the source code and provide different implementations for each one.

Getting the source of an AST

A macro is passed with a named parameter to_source which is a function able to get the Python code for an AST.

Expand macros

Use the named parameter expand_macros with an AST to expand the macros in that AST. This is useful to expand innermost macros first.

Examples

mcpy focuses on the mechanisms to expand macros, not in authoring tools or macros libraries. Anyway, a demo folder is provided to see mcpy in actions. Simply navigate to it and run a Python console, then import run:

import run