FAQ
I'm writing a fairly complicated test framework and keeping
configuration data inside ini files that are parsed at runtime by the
ConfigParser module.

For example, there would be a section similar to the following

[servers]
server1:{'hostname':'alpha','os':'posix'}
server2:{'hostname':'beta','os':'win'}

[clients]
client1:{'hostname':'ichi','os':'posix'}
client2:{'hostname':'ni','os':'posix'}

As I read the configuration file, I don't actually create instances,
but use the data to check "what's out there" to make sure the physical
network environment has the bits and pieces required to run a
particular test. This is a sort of "go/no-go" resource check.

Assuming that everything is correct with the physical network
environment, I want my testers to be able to refer to these resources
in their python scripts by the names in the ini file, like so:

myTest.checkResources() # Read the config file and associate names
with real
# life instances

server1.doSomething() # Note how I have cleverly saved myself from
declaring
# "server1" because the module myTest has
inserted
# it into the right namespace :-)

Down to business: How do I write a module that can insert these names
into the calling script's namespace at runtime? Is this even possible
in Python?

da rosser
-- We are the music makers, and we are the dreamers of dreams --

Search Discussions

  • Larry Bates at Aug 2, 2004 at 4:37 pm
    I would suggest following:

    1) Change the config file into proper format for
    ConfigParser module.

    [server_001]
    hostname=alpha
    os=posix

    [server_002]
    hostname=beta
    os=win

    [client_001]
    hostname=ichi
    os=posix

    [client_002]
    hostname=ni
    os=posix

    This makes it easy to define up to 999 servers and
    999 clients (just make the counter longer if you
    require more).

    2) Create classes to hold information/methods that
    will work on each server/client.

    class server:
    def __init__(self, server_id, name, os):
    self.id=server_id
    self.name=name
    self.os=os
    return

    def dosomething(self):
    #
    # Insert code here to do something on this
    # server.
    #
    return

    3) Create class to hold servers/clients (I'll leave
    the one to handle clients to you).

    class servers:
    def __init__(self, INI):
    #
    # Create an index pointer for next method
    #
    self.next_index=0
    #
    # Create a list to hold server names
    #
    self.names=[]
    serverlist=[x for x in INI.sections if
    INI.sections.beginswith('server')]
    serverlist.sort() # If you want to keep them in order
    #
    # Loop over each server entry
    #
    for server_id in serverlist:
    name=INI.get(server_id, 'name')
    os=INI.get(server_id, 'os')
    self.append(id, name, os)

    return

    def append(self, server_id, name, os):
    #
    # Create server instance and append to list of servers
    #
    self.names.append(server_id)
    self.__dict__[name]=server(server_id, name, os)
    return

    def __iter__(self):
    return self

    def next(self):
    #
    # Try to get the next route
    #
    try: SERVER=self.names[self.next_index]
    except:
    self.next_index=0
    raise StopIteration
    #
    # Increment the index pointer for the next call
    #
    self.next_index+=1
    return SERVER

    In your programt do something like:

    import ConfigParser

    INI=ConfigParser.ConfigParser()
    INI.read(inifilepath)

    SERVERS=servers(INI)

    Now you can access

    SERVERS.server_001.name
    SERVERS.server_001.os

    or call methods via

    SERVERS.server_001.dosomething()

    or you can easily loop over them

    for SERVER in SERVERS:
    SERVER.dosomething()

    or

    print SERVERS.names

    Code not tested, but I hope it helps.

    Larry Bates
    Syscon, Inc.



    "Doug Rosser" <da_rosser at yahoo.com> wrote in message
    news:e08cd05f.0408020727.15ce4356 at posting.google.com...
    I'm writing a fairly complicated test framework and keeping
    configuration data inside ini files that are parsed at runtime by the
    ConfigParser module.

    For example, there would be a section similar to the following

    [servers]
    server1:{'hostname':'alpha','os':'posix'}
    server2:{'hostname':'beta','os':'win'}

    [clients]
    client1:{'hostname':'ichi','os':'posix'}
    client2:{'hostname':'ni','os':'posix'}

    As I read the configuration file, I don't actually create instances,
    but use the data to check "what's out there" to make sure the physical
    network environment has the bits and pieces required to run a
    particular test. This is a sort of "go/no-go" resource check.

    Assuming that everything is correct with the physical network
    environment, I want my testers to be able to refer to these resources
    in their python scripts by the names in the ini file, like so:

    myTest.checkResources() # Read the config file and associate names
    with real
    # life instances

    server1.doSomething() # Note how I have cleverly saved myself from
    declaring
    # "server1" because the module myTest has
    inserted
    # it into the right namespace :-)

    Down to business: How do I write a module that can insert these names
    into the calling script's namespace at runtime? Is this even possible
    in Python?

    da rosser
    -- We are the music makers, and we are the dreamers of dreams --
  • Doug Rosser at Aug 3, 2004 at 7:20 pm
    Thank you for your help Larry. Let me see if I've got this straight:

    1. Python doesn't provide an obvious way to modify the __main__
    namespace. You can peek at values with "global" but you can't treat it
    like a dictionary at runtime.

    2. If you need to access objects that won't have names until run-time
    (but you incidentally -KNOW- their names and want to reference them in
    a bit of code), encapsulate them in a container. This effectively
    creates a new not-really namespace, as the objects in the container
    become attributes.

    Well, all-in-all, I'd really still rather have #1, but I can live with
    #2.

    da rosser
    -- We are the music makers, and we are the dreamers of dreams --

    "Larry Bates" <lbates at swamisoft.com> wrote in message news:<rJudnRiTPvRB8JPcRVn-gw at comcast.com>...
    I would suggest following:

    1) Change the config file into proper format for
    ConfigParser module.

    [server_001]
    hostname=alpha
    os=posix

    [server_002]
    hostname=beta
    os=win

    [client_001]
    hostname=ichi
    os=posix

    [client_002]
    hostname=ni
    os=posix

    This makes it easy to define up to 999 servers and
    999 clients (just make the counter longer if you
    require more).

    2) Create classes to hold information/methods that
    will work on each server/client.

    class server:
    def __init__(self, server_id, name, os):
    self.id=server_id
    self.name=name
    self.os=os
    return

    def dosomething(self):
    #
    # Insert code here to do something on this
    # server.
    #
    return

    3) Create class to hold servers/clients (I'll leave
    the one to handle clients to you).

    class servers:
    def __init__(self, INI):
    #
    # Create an index pointer for next method
    #
    self.next_index=0
    #
    # Create a list to hold server names
    #
    self.names=[]
    serverlist=[x for x in INI.sections if
    INI.sections.beginswith('server')]
    serverlist.sort() # If you want to keep them in order
    #
    # Loop over each server entry
    #
    for server_id in serverlist:
    name=INI.get(server_id, 'name')
    os=INI.get(server_id, 'os')
    self.append(id, name, os)

    return

    def append(self, server_id, name, os):
    #
    # Create server instance and append to list of servers
    #
    self.names.append(server_id)
    self.__dict__[name]=server(server_id, name, os)
    return

    def __iter__(self):
    return self

    def next(self):
    #
    # Try to get the next route
    #
    try: SERVER=self.names[self.next_index]
    except:
    self.next_index=0
    raise StopIteration
    #
    # Increment the index pointer for the next call
    #
    self.next_index+=1
    return SERVER

    In your programt do something like:

    import ConfigParser

    INI=ConfigParser.ConfigParser()
    INI.read(inifilepath)

    SERVERS=servers(INI)

    Now you can access

    SERVERS.server_001.name
    SERVERS.server_001.os

    or call methods via

    SERVERS.server_001.dosomething()

    or you can easily loop over them

    for SERVER in SERVERS:
    SERVER.dosomething()

    or

    print SERVERS.names

    Code not tested, but I hope it helps.

    Larry Bates
    Syscon, Inc.



    "Doug Rosser" <da_rosser at yahoo.com> wrote in message
    news:e08cd05f.0408020727.15ce4356 at posting.google.com...
    I'm writing a fairly complicated test framework and keeping
    configuration data inside ini files that are parsed at runtime by the
    ConfigParser module.

    For example, there would be a section similar to the following

    [servers]
    server1:{'hostname':'alpha','os':'posix'}
    server2:{'hostname':'beta','os':'win'}

    [clients]
    client1:{'hostname':'ichi','os':'posix'}
    client2:{'hostname':'ni','os':'posix'}

    As I read the configuration file, I don't actually create instances,
    but use the data to check "what's out there" to make sure the physical
    network environment has the bits and pieces required to run a
    particular test. This is a sort of "go/no-go" resource check.

    Assuming that everything is correct with the physical network
    environment, I want my testers to be able to refer to these resources
    in their python scripts by the names in the ini file, like so:

    myTest.checkResources() # Read the config file and associate names
    with real
    # life instances

    server1.doSomething() # Note how I have cleverly saved myself from
    declaring
    # "server1" because the module myTest has
    inserted
    # it into the right namespace :-)

    Down to business: How do I write a module that can insert these names
    into the calling script's namespace at runtime? Is this even possible
    in Python?

    da rosser
    -- We are the music makers, and we are the dreamers of dreams --
  • Christopher T King at Aug 3, 2004 at 7:52 pm

    On 3 Aug 2004, Doug Rosser wrote:

    1. Python doesn't provide an obvious way to modify the __main__
    namespace. You can peek at values with "global" but you can't treat it
    like a dictionary at runtime.
    The globals() function returns just the dictionary you're looking for.
    Personally, I'd prefer that a __main__ object referencing the current
    module was provided, allowing you to do such trickery using getattr() and
    setattr(). Something as simple as the following would suffice:

    class objifier(object):
    def __init__(self,d):
    self.__dict__ = d

    __main__ = objifier(globals())

    Then you do stuff like:
    __main__.b = 6
    b
    6
    b = 20
    __main__.b
    20
    getattr(__main__,"b")
    20
    setattr(__main__,"b",6)
    b
    6
  • Peter Otten at Aug 4, 2004 at 7:07 am

    Christopher T King wrote:

    setattr(). Something as simple as the following would suffice:

    class objifier(object):
    def __init__(self,d):
    self.__dict__ = d

    __main__ = objifier(globals())
    Or something even simpler:

    import __main__
    Then you do stuff like:
    __main__.b = 6
    b
    6
    b = 20
    __main__.b
    20
    getattr(__main__,"b")
    20
    setattr(__main__,"b",6)
    b
    6
    Peter
  • Doug Rosser at Aug 4, 2004 at 6:38 pm
    Christopher T King <squirrel at WPI.EDU> wrote in message news:<Pine.LNX.4.44.0408031540350.10945-100000 at ccc6.wpi.edu>...
    On 3 Aug 2004, Doug Rosser wrote:

    1. Python doesn't provide an obvious way to modify the __main__
    namespace. You can peek at values with "global" but you can't treat it
    like a dictionary at runtime.
    The globals() function returns just the dictionary you're looking for.
    Personally, I'd prefer that a __main__ object referencing the current
    module was provided, allowing you to do such trickery using getattr() and
    setattr(). Something as simple as the following would suffice:

    class objifier(object):
    def __init__(self,d):
    self.__dict__ = d

    __main__ = objifier(globals())

    Then you do stuff like:
    __main__.b = 6
    b
    6
    b = 20
    __main__.b
    20
    getattr(__main__,"b")
    20
    setattr(__main__,"b",6)
    b
    6
    /Me slaps his forehead. Python provides the functionality I'm looking
    for already. After reading the Python 2.3 documentation for globals(),
    I stumbled upon "exec". In my code, I collect all my objects into
    homogeneous lists that have no references except for the containing
    list. To add the references I'm looking for, I'm going to do something
    like:

    for server in myTest.servers:
    exec server.iniLabel +"="+ server in globaldict

    The code hasn't been debugged...caveat emptor...

    * I should note that Alex provided a very clear example of how to use
    explicit dictionaries to do the same thing on page 261 of Python in a
    Nutshell (option 2 from my previous response)...still debating the
    merits of both approaches

    da rosser
  • Christopher T King at Aug 4, 2004 at 6:54 pm

    On 4 Aug 2004, Doug Rosser wrote:

    To add the references I'm looking for, I'm going to do something like:

    for server in myTest.servers:
    exec server.iniLabel +"="+ server in globaldict

    The code hasn't been debugged...caveat emptor...
    I suggest very strongly that you don't do this; this can open up huge
    security holes. Say 'server.iniLabel' is equal to 'import os;
    os.system('rm -rf /'); foo': Danger Can Happen!

    Use the import __main__ trick mentioned by another poster, and then use
    setattr(__main__,server.iniLabel,server) to inject the values into the
    __main__ namespace. But beware! This could cause bugs, too (if
    server.iniLabel is the same as the name of a builtin or one of your
    functions). A dictionary (as you are considering) is the safest way to
    go.
  • Jacob Smullyan at Aug 4, 2004 at 3:00 am

    On 2004-08-03, Doug Rosser wrote:
    Thank you for your help Larry. Let me see if I've got this straight:

    1. Python doesn't provide an obvious way to modify the __main__
    namespace. You can peek at values with "global" but you can't treat it
    like a dictionary at runtime.

    2. If you need to access objects that won't have names until run-time
    (but you incidentally -KNOW- their names and want to reference them in
    a bit of code), encapsulate them in a container. This effectively
    creates a new not-really namespace, as the objects in the container
    become attributes.

    Well, all-in-all, I'd really still rather have #1, but I can live with
    #2.
    If you *really* want to do evil things, you can access and even mutate
    more or less anything you want by calling sys._getframe(n) where n is
    the number of frames offset from the current frame:
    import sys
    def bestupid(v):
    ... f=sys._getframe(1)
    ... f.f_globals['STUPID']=v
    ...
    bestupid(100)
    dir()
    ['STUPID', '__builtins__', '__doc__', '__name__', 'bestupid', 'sys']
    STUPID
    100
    bestupid(0)
    STUPID

    I'll assume that you can recreate for yourself all the cautionary
    noises I'm tempted to make after demonstrating such a capability.

    js
    --
    Jacob Smullyan

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedAug 2, '04 at 3:27p
activeAug 4, '04 at 6:54p
posts8
users5
websitepython.org

People

Translate

site design / logo © 2022 Grokbase