Dynamically add Class to Modules

C

callmebill

I'm trying to add a class to a module at runtime. I've seen examples
of adding a method to a class, but I haven't been able to suit it to my
needs.

As part of a testsuite, I have a main process X that searches
recursively for python test files. Those files typically have a global
"isSupported" method, in which the file tells the test searcher "do or
do not run me", as well as the typical TestName_TestCase class, with a
testMyTest method.

For numerous and reasonable reasons, the TestName_TestCase class must
be generated at runtime (i cannot use any pre-processing scripts to
generate the testcase files). So the external runner has to look into
each testcase file, determine if it is supported, expand out the
test-class code, and add that new class to that testcase in memory.

I hope this picture helps:


#-------- atestcase.py --------
def isSupported():
""" do a real check"""
return True


ThisTestName = "foo"
TestCode = \
"""
class %s_TestCase:
def __init__( self ):
""" do some stuff"""

def test_%s( self ):
""" run the test """
"""
#------------------------------------


#------- The external runner --------

(essentially)
import atestcase.py
if atestcase.isSupported():
# Run this test

(here's what i'm trying to figure out)
#--> expand atestcase.TestCode out to include "foo"
#--> make the testcode a class
#--> add the new foo_TestCase class to
# the atestcase module

#-------------------------------------


So: Does anyone know how dynamically generate a class, and add it to a
"module" that is already in memory?

Thanks so much in advance. My flu is heating up my brain pretty badly,
so please ask me if I have to clarify anything above.
 
M

Michael Spencer

I'm trying to add a class to a module at runtime. I've seen examples
of adding a method to a class, but I haven't been able to suit it to my
needs.

As part of a testsuite, I have a main process X that searches
recursively for python test files. Those files typically have a global
"isSupported" method, in which the file tells the test searcher "do or
do not run me", as well as the typical TestName_TestCase class, with a
testMyTest method.

For numerous and reasonable reasons, the TestName_TestCase class must
be generated at runtime (i cannot use any pre-processing scripts to
generate the testcase files). So the external runner has to look into
each testcase file, determine if it is supported, expand out the
test-class code, and add that new class to that testcase in memory.

I hope this picture helps:


#-------- atestcase.py --------
def isSupported():
""" do a real check"""
return True


ThisTestName = "foo"
TestCode = \
"""
class %s_TestCase:
def __init__( self ):
""" do some stuff"""

def test_%s( self ):
""" run the test """
"""
#------------------------------------


#------- The external runner --------

(essentially)
import atestcase.py
if atestcase.isSupported():
# Run this test

(here's what i'm trying to figure out)
#--> expand atestcase.TestCode out to include "foo"
#--> make the testcode a class
#--> add the new foo_TestCase class to
# the atestcase module

#-------------------------------------


So: Does anyone know how dynamically generate a class, and add it to a
"module" that is already in memory?

Thanks so much in advance. My flu is heating up my brain pretty badly,
so please ask me if I have to clarify anything above.
Bill,
I think this should do it:

import atestcase as T
exec T.TestCode % T.ThisTestName in T.__dict__

If you want to substitute ThisTestName more than once, you might be better off
using the %(name)s form, supplied with a dictionary {name: "foo"}, or you could
look at the new string.Template class for easier string subsitution.

Michael
 
M

Mike Meyer

So: Does anyone know how dynamically generate a class, and add it to a
"module" that is already in memory?

How about adding a step:

generate your class to a file
import the file as a module.
bind a name in "module" to the class in the imported module.

<mike
 
C

callmebill

Hi Michael... It didn't seem to take. Here is some of the actual code:

[[[[[[[[[[ from the runner ]]]]]]]]]]]]]
print "+++++++++++++++++++++++++++++++++++++++"
print "::Dir before exec:",dir(testModule)
import CodeGenBase
if hasattr( testModule,"TheTestCode" ):
print testModule.TheTestCode
%(testModule.TheTestName,

testModule.TheTestName )
exec testModule.TheTestCode
%(testModule.TheTestName,

testModule.TheTestName )

else:
print "PASSING"
print "::Dir after exec:",dir( testModule )
print "+++++++++++++++++++++++++++++++++++++++"

[[[[[[[[[[[[[[[[[[[ from the test file ]]]]]]]]]]]]]]]]]]]]
TheTestName = "FOO_TEST_NAME"
TheTestCode = \
"""class %sTestCase( CodeGenBase.CodeGenBase ):
def __init__( self,methodName ):
CodeGenBase.CodeGenBase.__init__( self,methodName )

def test%s(self):
self.SetupAndRunConfigTxtTests()

"""


......It doesn't look like the new class is sticking. Below is some
output:
+++++++++++++++++++++++++++++++++++++++
::Dir before exec: ['BuildRunBase', 'CodeGenBase', 'ConfigHelper',
'TheTestCode'
, 'TheTestName', '__builtins__', '__doc__', '__file__', '__name__',
'isSupported
', 'os', 'sys']
class FOO_TEST_NAMETestCase( CodeGenBase.CodeGenBase ):
def __init__( self,methodName ):
CodeGenBase.CodeGenBase.__init__( self,methodName )

def testFOO_TEST_NAME(self):
self.SetupAndRunConfigTxtTests()


::Dir after exec: ['BuildRunBase', 'CodeGenBase', 'ConfigHelper',
'TheTestCode',
'TheTestName', '__builtins__', '__doc__', '__file__', '__name__',
'isSupported'
, 'os', 'sys']
+++++++++++++++++++++++++++++++++++++++



Hopefully I just missed something obvious, which happens all too often.
Any ideas?

Thanks again for the help!
 
C

callmebill

Oh! I see what I missed. I didn't supply the namespace into which the
new class was going to be added (correct that statement, please, if it
is incorrect).

So by using this slight modification, thinks seemed to work:
exec testModule.TheTestCode %(testModule.TheTestName,

testModule.TheTestName ) in testModule.__dict__

....and boom it appeared in the 2nd dir.

Did i do good?
 
M

Michael Spencer

exec testModule.TheTestCode %(testModule.TheTestName, testModule.TheTestName )

....

Try changing that to exec ~ in testModule.__dict__

otherwise, your class statement gets executed in the current scope

Michael
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,782
Latest member
ThomasGex

Latest Threads

Top