2012-09-10 98 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