[BangPypers] How to create Debug and Release code in Python

Jeff Rush jeff at taupro.com
Tue Jun 16 08:27:35 CEST 2009


Vishal wrote:
> 
> *Is there a way to create a conditionally compilable Python script
> ?* Some facility that would prevent from code getting compiled into
> ".pyc"....something like the old #ifdef #endif preprocessor
> directives....is there a Python preprocessory available :)

I've given this more thought.  In the April 2009 issue of Python
Magazine is a wonderful article by Paul McGuire on writing Domain
Specific Languages.  It shows how to intercept the import of specific
types of files to preprocess the source before compiling it into
bytecode.  I played with those ideas to see what could be done for your
case.

So say you had a module marked up with special commenting like:

--- cut here --- abc.pyp
def main():
    print "Hello"  #? DEBUG
    print "There"  #? DEBUG2
    print "World"
--- cut here --- abc.pyp

Then in your main module you could do the following:

--- cut here --- demo.py
import cond_importer # can put in site.py for global application

import abc
abc.main()
--- cut here --- demo.py

Now you run the program normally and get:

$ python2.5 demo.py
Hello
There
World

or you can filter out lines using:

$ EXCLUDES=DEBUG python2.5 demo.py
There
World

or even:

$ EXCLUDES=DEBUG:DEBUG2 python2.5 demo.py
World

The magic to make this happen is just:

--- cut here --- cond_import.py
from __future__ import with_statement # for Python < 2.6

import os
import imputil
import re

patt = re.compile(r".*#\? (?P<tag>[_a-zA-Z][_a-zA-Z0-9]*)$")

try: # construct a set of tags to exclude in .py source
    pyexcludes = frozenset(os.environ['EXCLUDES'].split(':'))
except Exception:
    pyexcludes = frozenset()

def preprocess_source(filepath, fileinfo, filename):

    src = []
    with file(filepath, 'r') as f:
        for line in f:
            m = patt.match(line)
            if m is None or m.group('tag') not in pyexcludes:
                src.append(line)

        src = '\n'.join(src)
        codeobj = compile(src, filepath, 'exec')

    # create return tuple:
    #   import flag (0=module, 1=package)
    #   code object
    #   dictionary of variable definitions
    return 0, codeobj, {}

importer = imputil.ImportManager()
importer.add_suffix('.pyp', preprocess_source)
importer.install()
--- cut here --- cond_import.py

I arbitrarily chose a file extension of .pyp for files to preprocess but
 you could use anything.  And the tags to exclude could instead be tags
to include.  For handling packages (dirs) instead of modules you'd have
to add a test for file or directory and change the code a bit.

Anyway it raises some interesting possibilities of preprocessing.
Python is just so cool.

-Jeff


More information about the BangPypers mailing list