Question

What I want to do is something like this:

template.py

def dummy_func():
    print(VAR)
# more functions like this to follow

fabfile.py
# this gets called by fabric (fabfile.org)
# safe to think of it as ant build.xml

import template
template.VAR = 'some_val'
from template import *

Namely I have a template module other modules should 'extend' contributing the required variables. Can this be done in a functional manner (as opposed to object inheritance)?

EDIT: Added a bit more code.

Was it helpful?

Solution

I'm not sure what you mean by "a functional manner" -- do you mean, as in functional programming? That's not going to happen (since you're intrinsically trying to modify an object, which is the reverse of FP). Or do you mean something like "a way that works"?

For the latter interpretation, the big problem is the import * part -- among the many problems that suggest not using that, you're going to be running smack into one: it performs a snapshot of whatever module-level names are bound at the time (or just those listed in __all__ in the module, if that's defined) -- future changes to the bindings of names will never be reflected in modules that previously did the import *.

Why do you believe you need to merge the template_module's namespace into that of the importing module? If you just did a regular import template_module as tm, then simply referring to all the relevant names as tm.this, tm.that will work just fine (including picking up all changes to the bindings up to the instant of use -- in other words, it uses the "late binding" approach that you appear to require here).

OTHER TIPS

If you change a property of a module in one place, it will be the same in other places too. Proof:

Create a file '/tmp/test1.py':

imoprt os
os.path = '' # set os.path (module) to a mere string
os.zzz = 'zzz'

Then

cd /tmp && python

>>> dir(test)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'os', 'z']
>>> test.os
<module 'os' from '/usr/lib/python2.6/os.pyc'>
>>> test.os.path
''
>>> import os
>>> os.path
''
>>> os.zzz
'zzz'

Now os.path is an empty string even in the main application, and zzz is everywhere too.

Turns out this has a fabric-centric solution.
So you have an abstract some__fab__template.py and a concrete fabfile.py that should 'extend' the template contributing some required variables (e.g. project name).
I've implemented it utilizing fab's env dictionary.
In template file you reference env.VAR and in the 'concrete' fabfile.py you do this:

from fabric.api import *
env.VAR = 'some value'
import some__fab__template

def dist():
    some__fab__template.dist()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top