469,579 Members | 1,082 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,579 developers. It's quick & easy.

Mucking with the calling scripts namespace (For a good reason, honest!)

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 --
Jul 18 '05 #1
7 1225
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*******@yahoo.com> wrote in message
news:e0**************************@posting.google.c om...
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 --

Jul 18 '05 #2
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" <lb****@swamisoft.com> wrote in message news:<rJ********************@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*******@yahoo.com> wrote in message
news:e0**************************@posting.google.c om...
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 --

Jul 18 '05 #3
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

Jul 18 '05 #4
On 2004-08-03, Doug Rosser <da*******@yahoo.com> 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

0

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
Jul 18 '05 #5
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

Jul 18 '05 #6
Christopher T King <sq******@WPI.EDU> wrote in message news:<Pi**************************************@ccc 6.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
Jul 18 '05 #7
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.

Jul 18 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

33 posts views Thread by Jerry Boone | last post: by
26 posts views Thread by Marius Horak | last post: by
4 posts views Thread by Bob | last post: by
1 post views Thread by Hani Atassi | last post: by
7 posts views Thread by Sharon | last post: by
4 posts views Thread by guiromero | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.