Changing behaviour of namespaces

Discussion in 'Python' started by Mikael Olofsson, Sep 21, 2006.

  1. Hi!

    This is in Python 2.3.4 under WinXP.

    I have a situation where I think changing the behaviour of a namespace
    would be very nice. The goal is to be able to run a python file from
    another in a separate namespace in such a way that a NameError is not
    raised if a non-existing variable is used in the file. The file that I
    want to run is taken out of context, and some needed variables may be
    missing that are normally there when used in the intended context. OK!
    When I run it out of context, I do not want the execution to stop
    half-way through the file based on NameErrors, instead a predefined
    dummy variable should be used. The question is: Can I achieve that?

    Google didn't give me much, so I experimented a bit: First, I created a
    dummy object, which is meant to be used when a variable is missing:

    class dummyClass(object):
    dummyObject = dummyClass()

    The actual dummy object is supposed to be a bit more complicated than
    that. The next step was to subclass dict:

    class forgivingDict(dict):
    def __init__(self,*args,**kwargs):
    def __getitem__(self,key):
    print ' Getting', key
    return dict.__getitem__(self,key)
    except KeyError:
    return dummyObject
    def __setitem__(self,key,value):
    print ' Setting', key, 'to', value
    def __contains__(self,item):
    return True
    def __repr__(self):
    return 'forgivingDict(%s)' % (dict.__repr__(self),)

    Then I tried to execute a file using a forgivingDict() as namespace:

    ns = forgivingDict()
    execfile(filePath, ns)

    A file containing the following passes perfectly OK:

    a = 0
    b = a

    But a file containing the following produces a NameError:

    b = a

    The error traceback for the interested:

    Traceback (most recent call last):
    File "//charm/mikael/My
    Documents/Programmering/Python/Tester/", line 130, in ?
    execfile('', ns)
    File "", line 1, in ?
    b = a
    NameError: name 'a' is not defined

    Now, that is exactly what is to expect if ns is a dict(), but I was
    hoping that b would have ended up as dummyObject when ns is a
    forgivingDict(). One thing: Nothing is printed out when execfile-ing the
    files, which means that the methods forgivingDict.__getitem__ and
    forgivingDict.__setitem__ are never used. My guess was that the
    execution done by execfile uses dict.__getitem__(ns, key) and
    dict.__setitem__(ns,key,value) instead of ns[key] and ns[key]=value when
    getting and setting variables. That is probably intentional from the
    developers and done that way for a good reason.

    Alternative test: I've tried to replace __builtin__.dict with my
    forgivingDict, slightly modified to make sure that the inheritance still
    works, which didn't change anything. So it seams that the execution done
    by execfile does *not* use dict.__getitem__(ns, key) and
    dict.__setitem__(ns,key,value) after all, but something else. Probably
    the original dict is around somewhere else, and execfile uses the
    corresponding methods of that.

    My approach seems flawed. Any ideas? Can I somehow execute a complete
    file even if there are non-existent variables used somewhere? A
    try-except around the execfile statement is not an alternative, since
    that stops the execution where the error occurs.

    Should I perhaps read up on the compiler module? I mean: Using the
    compiler module to analyze the content of the file, and based on that
    updating my namespace before executing the file.

    Mikael Olofsson, Sep 21, 2006
    1. Advertisements

  2. Mikael Olofsson

    Peter Otten Guest

    Peter Otten, Sep 21, 2006
    1. Advertisements

  3. Thanks! As clear as possible. I will do that.

    FYI: I think I managed to achieve what I want in Py2.3 using the
    compiler module:

    def getNamesFromAstNode(node,varSet):
    if node.__class__ in (compiler.ast.Global,compiler.ast.Import):
    if node.__class__ in (compiler.ast.Name,):
    for subNode in node.getChildNodes():

    # Get all variable names that are referenced in the file:
    varSet = sets.Set()
    mainNode = compiler.parseFile(filePath)

    # Define a namespace and update it:
    ns = {}
    for varName in varSet:
    ns[varName] = dummyObject

    # Execute the file without NameErrors:

    Batteries included!

    Mikael Olofsson, Sep 21, 2006
  4. Mikael Olofsson

    Peter Otten Guest

    Clearly more elegant than:
    .... ns = dict((n, dummy) for n in names)
    .... try:
    .... execfile(filename, ns)
    .... except NameError, e:
    .... names.append(e[0][6:-16])
    .... else:
    .... break


    Peter Otten, Sep 21, 2006
  5. That sure is nicer. My solution looks like shooting mosquitoes with an
    elephant rifle i comparison. Thanks.

    Mikael Olofsson, Sep 21, 2006
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.