2012-09-10 82 views
0

我在第三方应用程序中使用jython。第三方应用程序有一些内置库foo。为了做一些(单元)测试,我们希望在应用程序之外运行一些代码。由于foo被绑定到应用程序,我们决定编写我们自己的模拟实现。如何更改导入库的名称?

但是有一个问题,我们在python中实现了我们的模拟类,而他们的类是在java中。因此,为了使用他们的代码,人们会做import foo,并且之后foo是模拟。但是,如果我们像这样导入python模块,我们将模块附加到名称上,因此必须编写foo.foo才能进入该类。

为了方便的原因,我们很乐意能写from ourlib.thirdparty import foo绑定foofoo - 。但是我们希望避免直接导入ourlib.thirdparty中的所有类,因为每个文件的加载时间需要相当长的一段时间。

有什么办法可以在python中做到这一点? (我没有导入挂钩跑远我想简单地从load_module返回类或覆盖了我写sys.modules(我认为这两种方法都是丑陋的,尤其是后来))

编辑

OK :这里是ourlib.thirdparty文件是什么样子的简化(没有魔法):

foo.py:

try: 
    import foo 
except ImportError: 
    class foo 
     .... 

ACTU盟友他们看起来像这样:

foo.py:

class foo 
    .... 

__init__.py in ourlib.thirdparty 
import sys 
import os.path 
import imp 
#TODO: 3.0 importlib.util abstract base classes could greatly simplify this code or make it prettier. 

class Importer(object): 
    def __init__(self, path_entry): 
     if not path_entry.startswith(os.path.join(os.path.dirname(__file__), 'thirdparty')): 
      raise ImportError('Custom importer only for thirdparty objects') 

     self._importTuples = {} 

    def find_module(self, fullname): 
     module = fullname.rpartition('.')[2] 

     try: 
      if fullname not in self._importTuples: 
       fileObj, self._importTuples[fullname] = imp.find_module(module) 

       if isinstance(fileObj, file): 
        fileObj.close() 
     except: 
      print 'backup' 
      path = os.path.join(os.path.join(os.path.dirname(__file__), 'thirdparty'), module+'.py') 
      if not os.path.isfile(path): 
       return None 
       raise ImportError("Could not find dummy class for %s (%s)\n(searched:%s)" % (module, fullname, path)) 

      self._importTuples[fullname] = path, ('.py', 'r', imp.PY_SOURCE) 

     return self 

    def load_module(self, fullname): 
     fp = None 
     python = False 

     print fullname 

     if self._importTuples[fullname][1][2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.PY_FROZEN): 
      fp = open(self._importTuples[fullname][0], self._importTuples[fullname][1][1]) 
      python = True 

     try: 
      imp.load_module(fullname, fp, *self._importTuples[fullname]) 
     finally: 
      if python: 
       module = fullname.rpartition('.')[2] 
       #setattr(sys.modules[fullname], module, getattr(sys.modules[fullname], module)) 
       #sys.modules[fullname] = getattr(sys.modules[fullname], module) 

       if isinstance(fp, file): 
        fp.close() 

       return getattr(sys.modules[fullname], module) 



sys.path_hooks.append(Importer) 
+5

':

所以,下面的代码将也完全为你工作? –

+0

什么是'ourlib.thirdparty'?那是你写的模拟python代码,还是java代码? – mgilson

+0

你需要'ourlib.thirdparty'中的其他类吗?你的第三段有点含糊。 – deadly

回答

0

正如其他人说,它是在Python这样一个普通的事情,在import声明iself有一个语法:

from foo import foo as original_foo,例如 - 甚至import foo as module_foo

而有趣的是,import statemente名称绑定到进口(模块sys of course), is a live reference to all imported modules, using their names as a key. This mechanism plays a key role in avoding that Python re-reads and re-executes and already imported module , when running (that is, if various of yoru modules or sub-modules import the same foo`模块,它只被读取一次 - 随后的导入使用存储在sys.modules中的引用)。

而且 - 除了“import ... as”语法,Python中的模块只是另一个对象:您可以在运行时为它们指定任何其他名称。从ourlib.thirdparty进口富作为foo`

import foo 
original_foo = foo 
class foo(Mock): 
    ... 
+0

嗨,不幸的是我不能使用模拟,因为它带有jython 3据我所知,而不是(j)ython 2.5。为了将myeslef转回到根目录:我用目前正在使用的代码更新了我的问题,稍微澄清一点,如果我可以自动进行这种重命名,为什么在可以的时候写'from ourlib.thirdpartylib.foo import foo'写'从ourlib.thirdpartylib导入foo',甚至更好'导入foo'。最后是最好的,那么你可以使用没有我们的模拟库(第三方lib请求然后)的代码。所有需要的是改变导入钩子中的find方法。 – ted

+0

...但适当的重命名是先决条件。 – ted