2016-10-22 16 views
4

私はPythonで猿パッチモジュールをラップしようとしています。私は既存のコードに干渉しない、これを実装するきれいな手段を開発しようとしています。私は別の_MODULE_MODULEを交換したいと思いますMODULEPythonオーバーレイ:猿パッチの場合

from MODULE import CLASS 

からいくつかのCLASSをインポートするスクリプト考える

問題

_MODULE_は元のMODULEのパッチです。私が見ることができる最もクリーンなインターフェースは次のとおりです。

from overlay import MODULE # Switches MODULE for _MODULE 
from MODULE import CLASS # Original import now uses _MODULE_ 

これは基本的に猿のパッチのクラス、機能、および方法と同じ方法でモジュールを猿にパッチすることです。これが正しく行われれば、プロジェクト固有の方法で一貫してパッチコードを修正できると私は信じています。

これを実装する最良の方法は何ですか?

+0

私の質問をあまりにも幅広く、おそらくそれは曖昧であると投票する理由がわかりませんが、確かに焦点が絞られた問題です。おそらく私は少し冗長になっていますか?どちらの方法でも、私は全体の内容を編集し、それをいくつか整理しました。 – Carel

+1

投稿で質問を見つけることは本当に難しいです。あなたは、巨大なテキストの壁やコーディング例を綿密に読まなければなりません。おそらく、あなたは質問を先頭にして、問題を示すすべてのコードを提供する必要があります。 –

+0

私はMWEを整理しましたが、誰かが尋ねると回答として投稿しますが、返信されていないステータスを保存するためには、今すぐ中止しています。うまくいけば、これはより堅牢なアプローチに扉を開いたままにする。 – Carel

答えて

3
>>> import wrapt 
>>> @wrapt.when_imported('collections') 
... def hook(collections): 
...  OldOrderedDict = collections.OrderedDict 
...  class MyOrderedDict(OldOrderedDict): 
...   def monkey(self): 
...    print('ook ook') 
...  collections.OrderedDict = MyOrderedDict 
...  
>>> from collections import OrderedDict 
>>> OrderedDict().monkey() 
ook ook 
0

@ウィムの答えは確かに良いですが、私はこれをしばらく参考にしていますので、ここで私の最高のバッシュです。私は次のフォルダ/ファイル構造を前提としています

import importlib 
import inspect 
import builtins 
import os 
from pathlib import Path 

modsep  = '.' 

class OverlayImporter(object): 

def __init__(self, *args, path = None, root = None, _import_ = __import__, **kvps): 
    super().__init__(*args, **kvps) 
    self.mask = "_{}_" 
    self.root = Path(root or os.path.dirname(inspect.getmodule(inspect.stack()[1][0]).__file__)) 
    self.mods = self.modules() 
    # Substitutes Import Functionality 
    builtins.__import__ = self 
    self.imp = _import_ 
    self.lom = [] 

def __call__(self, name, *args) : # (self, *args, *kvps): 
    # Hooks the import statement 
    if self.mapToTarget(name) in self.mods.keys() : 
    if name in self.lom : 
    return self.imp(name, *args) 
    self.lom.append(name) 
    return importlib.import_module(self.mapToTarget(name)) # This is a little black magic as we ignore the args 
    return self.imp(name, *args) 

def mapToTarget(self, name) : 
    """Maps request to the overlay module""" 
    # Converts PACKAGE.MODULE to overlay._PACKAGE_._MODULE_ 
    return modsep.join([self.mask.format(part) for part in name.split(modsep)]) 

def modules(self) : 
    """ Lists the overlays implemented within a directory """ 
    ext = '.py' 
    mod = lambda parts, ext : [part[:-len(ext)] if enum + 1 == len(parts) else part for enum, part in enumerate(parts)] 
    lst = [(mod(file.relative_to(self.root).parts, ext), file) for file in self.root.rglob('*'+ext)] 
    return {modsep.join(item[0][:-1]) if item[0][-1] == "__init__" else modsep.join(item[0]) : item[1] for item in lst} 

__main_.py以内に私は

を持っている: _decimal_.py

PACKAGE/ 
    overlay.py 
    _decimal_.py 
    __main__.py 

を私は次の行私が持っているoverlay.py

from decimal import * 
__version__ = "X.Y" 

が含まれます

from overlay import OverlayImporter 
OverlayImporter() 
import decimal 
print(decimal.__version__) 

メインファイルの最初の2行をコメントすると、パッチされたバージョンとパッチされていないバージョンの小数点が切り替わります。

関連する問題