1

I have python project that runs on multiple machines. I am using virtualenv to sync the python modules across the multiple machines. This works great. However I am pulling in some in-house baked SWIG *.so's packages into the env as well. These c++ shared objects have some far-reaching dependency nightmares which are difficult to reproduce on some of the machines. I don't need there code-functionality on a few of the devel machines. I would like have to rest of the python code load and continue rocking on without modification.

I would like to 'fake-the-module' loading on machines that dont have the modules. I wont be calling the code that actually exercises the SWIG *.so's methods.

example:

try:
   import swigpackagefoo.swigsubpackagebar
except ImportError:
   # magic code that defines the fake module, I want to define a bunch of class'es with 'pass'
   # so all the code deps would be happy. and I dont require the swig *.so to 
   # be installed on the devel system.
   # something along the lines of.
   __import__('swigpackagefoo.swigsubpackagebar')=class foo(object): pass

Note: I think its worth noting that when the module imports the *.so, on the prod machine the

type(swigpackagefoo)
# is 'module', also the 
type(swigpackagefoo.swigsubpackagebar)
# is also 'module'

so 'How do I define a module-in-line' in python?

I do not want to create the packages on the missing devel machines

i.e.: I DO-NOT want to create these files, because of module conflicts on the systems that work.

$ tree
  swigpackagefoo/__init__.py
  swigpackagefoo/swigsubpackagebar/__init__.py
Jeff Sheffield
  • 5,768
  • 3
  • 25
  • 32
  • 2
    Why can't you just `pass` in your exception clause? If those modules won't be used anyway, then you don't even need an object in the namespace with that name. Another option would be to populate a class which has the same layout as the module. – mgilson Dec 15 '12 at 02:17

2 Answers2

3

If I understand you correctly, you want to be able to "mock" the compiled module if it can't be imported?

So if in your swigsubpackagebar you have:

swigsubpackagebar.aFunc(aString) -> outString

Then you would want a "mock" module to support that same interface, but just not do anything.

Instead of trying to solve this with some on-the-fly module definition, just define another module that supplies the interface you want:

## swigMock.py ##
def aFunc(aString):
    return aString

Then structure your import statement like this:

## main.py ##
try:
   import swigpackagefoo.swigsubpackagebar as swigModule
except ImportError:
   import swigMock as swigModule

print swigModule.aFunc("FOO")

If swigsubpackagebar is actually a class, it's pretty much the same concept:

## swigMock.py ##
class swigsubpackagebar(object):
    pass

And again use the as keyword for naming it the same:

## main.py ##
try:
   import swigpackagefoo.swigsubpackagebar as swigClass
except ImportError:
   import swigMock.swigsubpackagebar as swigClass

aClass = swigClass()
jdi
  • 90,542
  • 19
  • 167
  • 203
  • Thanks 'Justin' I did follow your recipe to create Mock classes for the missing python modules. It worked great and served as a great way for me to fake in data for specific method calls. – Jeff Sheffield Dec 16 '12 at 07:30
0

yes you can!

import sys
import types

my_module = types.ModuleType('my_module')
sys.modules['my_module'] = my_module
my_code = '''
def f():
    print('my_module.f says hello')
'''
exec(my_code, my_module.__dict__)
my_module.f()

source: How to load a module from code in a string?

milahu
  • 2,447
  • 1
  • 18
  • 25