platform-specific overrides of functions and class methods (expanding on imputils demo code)

lkcl luke.leighton at googlemail.com
Sun Aug 16 14:08:39 CEST 2009


i've just had to put something together for pyjamas-desktop which may
prove to be useful to other people, so i'm pointing people in its
general direction, for archive purposes.

the purpose behind the platform override system is to allow
implementations of a common API, in python, to share the majority of
their codebase (modules, classes, functions etc.) _but_, for _very_
specific platform implementation purposes, allow for "overrides".

example:

test.py
def test():
   print "hello"

platform/testOverridingPlatformName.py:
def test():
   print "this is not kansas any more"

code is here:
http://pyjamas.svn.sourceforge.net/viewvc/pyjamas/trunk/pyjd/

modules to pay attention to: importers.py (a modified version of Demos/
imputils/importers.py) and modcompile.py.  setup/init function is very
simple - see __init__py.in last few lines.

on reading modcompile.py you may be forgiven for going "wtf????" but
basically PlatformParser loads the python source; turns it into an
AST; then also the "platform-specific" version is loaded and turned
into an AST; then, the two ASTs are handed to the "merge" function
which does a top-level "replace" of functions and a top-level
"replace" of class methods.

_theen_ the resultant "merged" AST is handed to a module which was
derived from compiler/pycodegen.py - none of the code in there can
cope with being handed an already-compiled AST so it was necessary to
make a class that did.  looking around on the internet i find quite a
few people asking about how to do this, so ... take a look at
modcompile.Module, and how it's used.  very simple.

i've disabled saving and detection of .pyc files for now, because the
job of loading code from .pyc should really be done by PlatformParser
(which understands the concept of... duh, a platform).   the _last_
thing that you want to happen is to run one platform's code, generate
some .pyc files, then change a config file to run a different back-end
platform, for example (which is possible with pyjamas-desktop) and end
up running the _wrong_ platform-specific code.

for those people wondering, "why in god's green earth would anyone
want to _do_ such a thing???" it's quite simple: the alternative is a
complete dog's dinner, in pyjamas:

def do_some_DOM_manipulation(document):
    # heeeere we go...
    if platform == 'hulahop' # this is for XULrunner
       do_some_stuff()
    elif platform == 'pywebkitgtk':
       do_something_different()
    elif platform == 'mshtml' # for pywin32 and comtypes....
       do_something_dreadful()
    else:
       do_the_default_here()

now imagine that across an API with ... four hundred functions.

i just... couldn't bring myself to do that.  not when the pyjs (python-
to-javascript) compiler _already_ solved this problem (thanks to james
tauber) by deploying the AST merge concept.

all i did was merge that with the imputils demo code so that, rather
than at compile-time the pyjs compiler goes and generates five
platform-specific versions of the same application, pyjamas-desktop at
_run_ time can do exactly the same thing.

but - it's a generic enough idea to be of value elsewhere - for
example, all the loooovely code in e.g. the setup distutils?  all
those looovely "if os.platform == 'win32'", and "if sys.this = 'posix'
" could be replaced with platform-specific overrides that got merged
at run-time, thus _dramatically_ simplifying the look and the
useability of the code.

enjoy.

l.



More information about the Python-list mailing list