Pythonで最小限のプラグインアーキテクチャを構築する


190

私は、かなり技術的な読者(科学者)が使用するPythonで書かれたアプリケーションを持っています。

ユーザーがアプリケーションを拡張できるようにするための良い方法、つまりスクリプト/プラグインアーキテクチャを探しています。

非常に軽量なものを探しています。ほとんどのスクリプトまたはプラグインは、サードパーティによって開発および配布されてインストールされることはありませんが、繰り返しのタスクを自動化し、ファイル形式のサポートを追加するために、ユーザーによって数分で作成されます。などプラグインは、最小限の定型コードを持つ必要があり、フォルダーへのコピー以外に「インストール」を必要としません(したがって、setuptoolsエントリーポイントのようなもの、またはZopeプラグインアーキテクチャは多すぎるように見えます)。

このようなシステムはすでにありますか、または私がアイデア/インスピレーションを探す必要がある同様のスキームを実装するプロジェクトはありますか?

回答:


150

Mineは基本的に、「プラグイン」と呼ばれるディレクトリであり、メインアプリはポーリングしてからimp.load_moduleを使用してファイルを取得し、モジュールレベルの構成パラメーターでよく知られたエントリポイントを探し、そこから移動します。私はプラグインがアクティブである一定のダイナミズムのためにファイル監視機能を使用していますが、それは便利です。

もちろん、「[Xは必要ない、複雑なもの] Xは不要です。軽量なものを使いたい」という要件は、Xを1つずつ再実装するというリスクを伴います。とはいえ、とにかくそれを楽しむことができないと言っているのではありません:)


26
どうもありがとう!私はあなたの投稿に基づいて小さなチュートリアルを書きました:lkubuntu.wordpress.com/2012/10/02/writing-a-python-plugin-api
MiJyn

9
impモジュールはの賛成で廃止されるimportlibのpython 3.4から始まる
b0fh

1
多くのユースケースでは、の代わりにimportlib.import_moduleを使用できますimp.load_module
Chris Arndt

58

module_example.py

def plugin_main(*args, **kwargs):
    print args, kwargs

loader.py

def load_plugin(name):
    mod = __import__("module_%s" % name)
    return mod

def call_plugin(name, *args, **kwargs):
    plugin = load_plugin(name)
    plugin.plugin_main(*args, **kwargs)

call_plugin("example", 1234)

それは確かに「最小」であり、エラーチェックがまったくなく、おそらく無数のセキュリティ問題があり、あまり柔軟ではありませんが、Pythonのプラグインシステムがいかにシンプルであるかを示しているはずです。

あなたはおそらくimpモジュールも調べたいと思いますが__import__os.listdirと、いくつかの文字列操作で多くのことができます。


4
私は変更するかもしれないと思うdef call_plugin(name, *args)def call_plugin(name, *args, **kwargs)、その後、とplugin.plugin_main(*args)plugin.plugin_main(*args, **kwargs)
ロン・クライン

12
python 3ではimp非推奨ですimportlib
アダムバクスター


25

その質問は非常に興味深いものですが、詳細を説明しない限り、答えるのはかなり難しいと思います。これはどのようなアプリケーションですか?GUIはありますか?コマンドラインツールですか?スクリプトのセット?ユニークなエントリーポイントなどを持つプログラム...

私が持っている少しの情報を考慮して、私は非常に一般的な方法で答えます。

プラグインを追加する必要があるとはどういう意味ですか?

  • おそらく、ロードするパス/ディレクトリをリストする設定ファイルを追加する必要があります。
  • もう1つの方法は、「plugin /ディレクトリ内のすべてのファイルがロードされる」と言うことですが、ユーザーにファイルの移動を要求するのは不便です。
  • 最後の中間オプションは、すべてのプラグインが同じplugin /フォルダーにあることを要求し、構成ファイルの相対パスを使用してそれらをアクティブ/非アクティブにすることです。

純粋なコード/設計プラクティスでは、ユーザーに拡張してほしい動作/特定のアクションを明確に決定する必要があります。共通のエントリポイント/常にオーバーライドされる一連の機能を特定し、これらのアクション内のグループを決定します。これが完了すると、アプリケーションを簡単に拡張できるはずです。

MediaWiki(PHPからインスピレーションを得たフックを使用した例ですが、言語は本当に重要ですか?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

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

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

水銀からインスピレーションを得た別の例。ここでは、拡張機能はhgコマンドライン実行可能ファイルにコマンドを追加するだけで、動作を拡張します。

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

どちらの方法でも、拡張機能の共通の初期化ファイナライズが必要になる場合があります。すべての拡張機能が実装する必要がある共通のインターフェイスを使用するか(2番目のアプローチに適しています。Mercurialはすべての拡張機能に対して呼び出されるreposetup(ui、repo)を使用します)、またはフック付きのアプローチを使用します。 hooks.setupフック。

しかし、繰り返しになりますが、より有用な回答が必要な場合は、質問を絞り込む必要があります;)


11

Marty Allchinの単純なプラグインフレームワークは、私が自分のニーズに使用するベースです。ぜひご覧になることをお勧めします。シンプルで簡単にハッキングできるものが必要な場合は、これは本当に良いスタートだと思います。Django Snippetsとしても見つけることができます。


私はpyduckをベースとしてそのようなことをしようとしています。
エドマウル

それは私が言うことができることから非常にDjango固有です。
Zoran Pavlovic 2013

3
@ZoranPavlovic:まったく、標準のPythonの一部の行ではありません。Djangoを使用する必要はありません。
エドマウル2013

11

私は引退した生物学者で、デジタルマイクログラフを扱い、SGiマシンで実行するには画像処理および分析パッケージ(技術的にはライブラリではありません)を作成する必要がありました。コードはCで記述し、スクリプト言語にはTclを使用しました。このようなGUIはTkを使用して作成されました。Tclに表示されたコマンドは、「extensionName commandName arg0 arg1 ... param0 param1 ...」という形式でした。つまり、スペースで区切られた単純な単語と数字です。Tclが「extensionName」サブストリングを見たとき、制御はCパッケージに渡されました。次に、レクサー/パーサー(lex / yaccで実行)を介してコマンドを実行し、必要に応じてCルーチンを呼び出しました。

パッケージを操作するコマンドは、GUIのウィンドウを介して1つずつ実行できますが、バッチジョブは、有効なTclスクリプトであるテキストファイルを編集することで実行されました。実行したいファイルレベルの操作を実行するテンプレートを選択し、コピーを編集して、実際のディレクトリとファイル名、およびパッケージコマンドを含めます。それは魅力のように働きました。まで...

1)世界はPCに変わり、2)スクリプトは約500行より長くなり、Tclの不明瞭な組織機能が実際に不便になり始めました。時は過ぎた ...

私は引退しました、Pythonは発明されました、そしてそれはTclの完璧な後継者のように見えました。PCで(かなり大きな)Cプログラムをコンパイルし、CパッケージでPythonを拡張し、Python / Gt?/ Tk?/?でGUIを実行するという課題に直面したことがないので、今は移植を行ったことがありません。 ?。ただし、編集可能なテンプレートスクリプトを使用するという古い考え方は、まだ機能しているようです。また、ネイティブPython形式でパッケージコマンドを入力することは、それほど大きな負担になりません。

packageName.command(arg0、arg1、...、param0、param1、...)

いくつかの余分なドット、括弧、およびカンマですが、それらは見事なものではありません。

誰かがPythonでlexとyaccのバージョンを実行したことを覚えています(試してください:http : //www.dabeaz.com/ply/ので)、それでもまだ必要な場合は、問題はありません。

このとりとめのないことのポイントは、Python自体が科学者が使用できる望ましい「軽量」フロントエンドであるように思えたということです。なぜそうではないと思うのか知りたいのですが、真剣に考えています。


後で追加:アプリケーションgeditは、プラグインが追加されることを予期しており、彼らのサイトには、数分見て回ったところにある簡単なプラグイン手順の最も明確な説明があります。試してください:

https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld

私はまだあなたの質問をよりよく理解したいと思います。1)科学者が(Python)アプリケーションをさまざまな方法で非常に簡単に使用できるようにしたいのか、2)科学者がアプリケーションに新しい機能を追加できるようにしたいのか、私にはわかりません。選択#1は、画像に直面した状況であり、そのため、現在のニーズに合わせて変更した汎用スクリプトを使用するようになりました。プラグインのアイデアに導いたのはチョイス#2ですか、それともコマンドの発行を実行不可能にするアプリケーションのいくつかの側面ですか?


2
リンクの腐敗修復:Geditプラグインが追加されました
wiki.gnome.org/Apps/Gedit/PythonPluginHowTo

1
現代の生物学者がどれほど幸運かをはっきりと簡潔に示しているので、これは美しい投稿です。彼/彼女にとって、pythonはモジュール開発者にいくつかの抽象化を提供するために使用されるモジュール式スクリプト言語であり、メインのCコードを解析する必要がないようにします。しかし今日では、Pythonですべてを行う代わりにCを学ぶ生物学者はほとんどいません。モジュールを作成するときに、メインのpythonプログラムの複雑さをどのように抽象化しますか?今から10年後、おそらくプログラムは絵文字で作成され、モジュールは一連のうなり声を含むオーディオファイルになるでしょう。そして多分それは大丈夫です。
JJ

10

Pythonデコレータを検索しているときに、シンプルだが便利なコードスニペットが見つかりました。それはあなたのニーズに合わないかもしれませんが、非常に刺激的です。

Scipy Advanced Python#Plugin Registration System

class TextProcessor(object):
    PLUGINS = []

    def process(self, text, plugins=()):
        if plugins is ():
            for plugin in self.PLUGINS:
                text = plugin().process(text)
        else:
            for plugin in plugins:
                text = plugin().process(text)
        return text

    @classmethod
    def plugin(cls, plugin):
        cls.PLUGINS.append(plugin)
        return plugin


@TextProcessor.plugin
class CleanMarkdownBolds(object):
    def process(self, text):
        return text.replace('**', '')

使用法:

processor = TextProcessor()
processed = processor.process(text="**foo bar**", plugins=(CleanMarkdownBolds, ))
processed = processor.process(text="**foo bar**")

1
注:この例でWordProcessor.pluginは、何も返さない(None)ので、CleanMdashesExtension後でクラスをインポートすると、だけがインポートされNoneます。プラグインクラスがそれ自体で有用な場合は、.pluginクラスメソッドを作成しreturn pluginます。
jkmacc 2017年

@jkmaccその通りです。コメントの13日後にスニペットを変更しました。ありがとうございました。
guneysus 2017年

7

Dr. Andre RobergeがPycon 2009で提供したさまざまなプラグインアーキテクチャについての素晴らしい議論を楽しんだ。彼は、本当に単純なものから始めて、プラグインを実装するさまざまな方法の概要を説明している。

一連の6つのブログエントリを伴うポッドキャスト(モンキーパッチの説明に続く第2部)として利用可能

決定を下す前に、すぐに聞いてみることをお勧めします。


4

最小限のプラグインアーキテクチャを探してここにたどり着いたところ、すべてがやり過ぎに思える多くのものが見つかりました。そこで、私はSuper Simple Python Pluginsを実装しました。これを使用するには、1つまたは複数のディレクトリを作成し__init__.py、それぞれに特殊ファイルをドロップします。それらのディレクトリをインポートすると、他のすべてのPythonファイルがサブモジュールとしてロードされ、それらの名前が__all__リストに配置されます。その後、それらのモジュールを検証/初期化/登録するのはあなた次第です。READMEファイルに例があります。


4

実際、setuptoolsは、プロジェクトのドキュメントから次の例のように、「プラグインディレクトリ」で機能します。 引用してい http //peak.telecommunity.com/DevCenter/PkgResources#locating-plugins

使用例:

plugin_dirs = ['foo/plugins'] + sys.path
env = Environment(plugin_dirs)
distributions, errors = working_set.find_plugins(env)
map(working_set.add, distributions)  # add plugins+libs to sys.path
print("Couldn't load plugins due to: %s" % errors)

長期的に見れば、setuptoolsは競合や要件の欠落なしにプラグインをロードできるため、はるかに安全な選択肢です。

もう1つの利点は、元のアプリケーションが気にする必要なく、同じメカニズムを使用してプラグイン自体を拡張できることです。


3

プラグインシステムへのもう1つのアプローチとして、Extend Meプロジェクトを確認できます。

たとえば、単純なクラスとその拡張を定義しましょう

# Define base class for extensions (mount point)
class MyCoolClass(Extensible):
    my_attr_1 = 25
    def my_method1(self, arg1):
        print('Hello, %s' % arg1)

# Define extension, which implements some aditional logic
# or modifies existing logic of base class (MyCoolClass)
# Also any extension class maby be placed in any module You like,
# It just needs to be imported at start of app
class MyCoolClassExtension1(MyCoolClass):
    def my_method1(self, arg1):
        super(MyCoolClassExtension1, self).my_method1(arg1.upper())

    def my_method2(self, arg1):
        print("Good by, %s" % arg1)

そしてそれを使ってみてください:

>>> my_cool_obj = MyCoolClass()
>>> print(my_cool_obj.my_attr_1)
25
>>> my_cool_obj.my_method1('World')
Hello, WORLD
>>> my_cool_obj.my_method2('World')
Good by, World

そして、舞台裏に隠されているものを示します。

>>> my_cool_obj.__class__.__bases__
[MyCoolClassExtension1, MyCoolClass]

extend_meための例では、メタクラスを経由してライブラリ操作するクラスの作成プロセスを、上記の新しいインスタンスを作成する際にMyCoolClass、我々は両方のサブクラスである新しいクラスのインスタンスだMyCoolClassExtensionMyCoolClassPythonのにそれらの両方の機能性を有する、感謝を多重継承

クラス作成をより適切に制御するために、このlibで定義されているメタクラスはほとんどありません。

  • ExtensibleType -サブクラス化により単純な拡張性を可能にする

  • ExtensibleByHashType -ExtensibleTypeに似ていますが、クラスの特殊なバージョンを構築する機能があり、基本クラスのグローバルな拡張とクラスの特殊なバージョンの拡張を可能にします

このlibはOpenERPプロキシプロジェクトで使用されていますでており、十分に機能しているようです。

実際の使用例については、OpenERPプロキシの「field_datetime」拡張をご覧ください

from ..orm.record import Record
import datetime

class RecordDateTime(Record):
    """ Provides auto conversion of datetime fields from
        string got from server to comparable datetime objects
    """

    def _get_field(self, ftype, name):
        res = super(RecordDateTime, self)._get_field(ftype, name)
        if res and ftype == 'date':
            return datetime.datetime.strptime(res, '%Y-%m-%d').date()
        elif res and ftype == 'datetime':
            return datetime.datetime.strptime(res, '%Y-%m-%d %H:%M:%S')
        return res

Recordこれは拡張可能なオブジェクトです。RecordDateTime拡張です。

拡張機能を有効にするには、拡張クラスを含むモジュールをインポートし、(上記の場合)Record基本クラスに拡張クラスが含まれるように作成されたすべてのオブジェクトは、すべての機能を持ちます。

このライブラリの主な利点は、拡張可能なオブジェクトを操作するコードが拡張機能について知る必要がなく、拡張機能が拡張可能なオブジェクトのすべてを変更できることです。


私はあなたがサブクラスからインスタンス化する意味だと思い、すなわちmy_cool_obj = MyCoolClassExtension1()代わりにmy_cool_obj = MyCoolClass()
pylang

いいえ、拡張可能なクラスは__new__メソッドをオーバーライドしているため、すべてのサブクラスを自動的に検索し、それらすべてのサブクラスである新しいクラスを構築し、この作成されたクラスの新しいインスタンスを返します。したがって、元のアプリケーションはすべての拡張機能について知っている必要はありません。このアプローチは、ライブラリを構築するときに役立ちます。これにより、エンドユーザーは動作を簡単に変更または拡張できます。上記の例では、MyCoolClassをライブラリで定義して使用することができ、MyCoolClassExtensionはエンドユーザーが定義できます。
FireMage 2016年

答えのために、もう1つの例が追加されました
FireMage 2016年

3

setuptoolsにはEntryPointがあります

エントリポイントは、ディストリビューションが他のディストリビューションで使用するためにPython関数(関数やクラスなど)を「アドバタイズ」するための簡単な方法です。拡張可能なアプリケーションとフレームワークは、特定の配布またはsys.path上のすべてのアクティブな配布から特定の名前またはグループのエントリポイントを検索し、アドバタイズされたオブジェクトを自由に検査またはロードできます。

AFAIKこのパッケージは、pipまたはvirtualenvを使用している場合は常に利用可能です。


2

@edomaurの答えを拡張すると、Marty Alchinの作業に触発された単純なプラグインフレームワークであるsimple_plugins(恥知らずなプラグイン)を見てみることをお勧めします。

プロジェクトのREADMEに基づく短い使用例:

# All plugin info
>>> BaseHttpResponse.plugins.keys()
['valid_ids', 'instances_sorted_by_id', 'id_to_class', 'instances',
 'classes', 'class_to_id', 'id_to_instance']

# Plugin info can be accessed using either dict...
>>> BaseHttpResponse.plugins['valid_ids']
set([304, 400, 404, 200, 301])

# ... or object notation
>>> BaseHttpResponse.plugins.valid_ids
set([304, 400, 404, 200, 301])

>>> BaseHttpResponse.plugins.classes
set([<class '__main__.NotFound'>, <class '__main__.OK'>,
     <class '__main__.NotModified'>, <class '__main__.BadRequest'>,
     <class '__main__.MovedPermanently'>])

>>> BaseHttpResponse.plugins.id_to_class[200]
<class '__main__.OK'>

>>> BaseHttpResponse.plugins.id_to_instance[200]
<OK: 200>

>>> BaseHttpResponse.plugins.instances_sorted_by_id
[<OK: 200>, <MovedPermanently: 301>, <NotModified: 304>, <BadRequest: 400>, <NotFound: 404>]

# Coerce the passed value into the right instance
>>> BaseHttpResponse.coerce(200)
<OK: 200>

2

私は時々、Pythonでプラグインフレームワークを検索している間、このスレッドを読むことに時間を費やしてきました。私はいくつか使用しましたが、それらには欠点がありました。2017年に私があなたの精査のために思いついたのは、インターフェースがなく、疎結合のプラグイン管理システムです。後でロードしてください。ここにあるチュートリアルにそれを使用する方法については。


2

pluginlibを使用できます。

プラグインは簡単に作成でき、他のパッケージ、ファイルパス、またはエントリポイントからロードできます。

必要なメソッドを定義して、プラグインの親クラスを作成します。

import pluginlib

@pluginlib.Parent('parser')
class Parser(object):

    @pluginlib.abstractmethod
    def parse(self, string):
        pass

親クラスを継承してプラグインを作成します。

import json

class JSON(Parser):
    _alias_ = 'json'

    def parse(self, string):
        return json.loads(string)

プラグインをロードします。

loader = pluginlib.PluginLoader(modules=['sample_plugins'])
plugins = loader.plugins
parser = plugins.parser.json()
print(parser.parse('{"json": "test"}'))

1
例をありがとう。私は1つの質問で苦労してきました。異なるパッケージからプラグインをロードする可能性について言及したので、おそらくすでにそれを考えていました。親クラスはどこにあるのかしら。通常、アプリケーションのパッケージ(おそらく別のソースコードリポジトリ)に含めることをお勧めしますが、プラグインのコードベースでどのように継承するのでしょうか。このためにアプリケーション全体をインポートしますか?または、Parserクラスまたは同様の抽象化のようなインターフェースコードを3番目のパッケージ(3番目のコードリポジトリ)に含める必要がありますか?
JAponte

1
親クラスはアプリケーションと同じコードベースに存在する必要がありますが、おそらく独自のモジュールに存在します。したがって、というパッケージの場合、親クラスを定義する場所にfooというモジュールが存在する可能性がありますfoo.parents。次に、プラグインはをインポートしfoo.parentsます。これはほとんどのユースケースでうまく機能します。'foo'自体もインポートされるため、循環インポートの可能性を回避するために、多くのプロジェクトではモジュールのルートを空のままにし、__main__.pyファイルまたはエントリポイントを使用してアプリケーションを起動します。
aviso

1

私は、Pythonの小さなプラグインシステムを探すために多くの時間を費やしてきました。しかし、私が考えたのは、自然で柔軟な継承がすでにある場合は、それを使用しないことです。

プラグインに継承を使用する場合の唯一の問題は、プラグインクラスが最も具体的(継承ツリーで最も低い)なのか分からないことです。

しかし、これは、基本クラスの継承を追跡するメタクラスで解決でき、最も特定のプラグイン(下の図の「ルート拡張」)から継承するクラスを構築できる可能性があります。

ここに画像の説明を入力してください

だから私はそのようなメタクラスをコーディングすることで解決策を思いつきました:

class PluginBaseMeta(type):
    def __new__(mcls, name, bases, namespace):
        cls = super(PluginBaseMeta, mcls).__new__(mcls, name, bases, namespace)
        if not hasattr(cls, '__pluginextensions__'):  # parent class
            cls.__pluginextensions__ = {cls}  # set reflects lowest plugins
            cls.__pluginroot__ = cls
            cls.__pluginiscachevalid__ = False
        else:  # subclass
            assert not set(namespace) & {'__pluginextensions__',
                                         '__pluginroot__'}     # only in parent
            exts = cls.__pluginextensions__
            exts.difference_update(set(bases))  # remove parents
            exts.add(cls)  # and add current
            cls.__pluginroot__.__pluginiscachevalid__ = False
        return cls

    @property
    def PluginExtended(cls):
        # After PluginExtended creation we'll have only 1 item in set
        # so this is used for caching, mainly not to create same PluginExtended
        if cls.__pluginroot__.__pluginiscachevalid__:
            return next(iter(cls.__pluginextensions__))  # only 1 item in set
        else:
            name = cls.__pluginroot__.__name__ + 'PluginExtended'
            extended = type(name, tuple(cls.__pluginextensions__), {})
            cls.__pluginroot__.__pluginiscachevalid__ = True
return extended

したがって、メタクラスで作成されたルートベースがあり、それから継承するプラグインのツリーがある場合、サブクラス化するだけで、最も具体的なプラグインから継承するクラスを自動的に取得できます。

class RootExtended(RootBase.PluginExtended):
    ... your code here ...

コードベースはかなり小さく(約30行の純粋なコード)、継承が許す限り柔軟です。

興味があれば、https://github.com/thodnev/pluginlibに参加してください。


1

Groundworkご覧ください

アイデアは、パターンやプラグインと呼ばれる再利用可能なコンポーネントを中心にアプリケーションを構築することです。プラグインは、から派生するクラスですGwBasePattern。基本的な例は次のとおりです。

from groundwork import App
from groundwork.patterns import GwBasePattern

class MyPlugin(GwBasePattern):
    def __init__(self, app, **kwargs):
        self.name = "My Plugin"
        super().__init__(app, **kwargs)

    def activate(self): 
        pass

    def deactivate(self):
        pass

my_app = App(plugins=[MyPlugin])       # register plugin
my_app.plugins.activate(["My Plugin"]) # activate it

コマンドラインインターフェイス、シグナリング、共有オブジェクトなど、より高度なパターンも処理できます。

Groundworkは、プラグインを上記のようにプログラムでアプリにバインドするか、を介して自動的に検出しsetuptoolsます。プラグインを含むPythonパッケージは、特別なエントリポイントを使用してこれらを宣言する必要がありますgroundwork.plugin

ここにドキュメントがあります。

免責事項:私はGroundworkの作者の一人です。


0

現在のヘルスケア製品には、インターフェースクラスで実装されたプラグインアーキテクチャがあります。私たちの技術スタックは、Python for API上のDjangoとフロントエンド用のnodejs上のNuxtjsです。

私たちの製品用に作成されたプラグインマネージャーアプリは、基本的にはDjangoとNuxtjsに準拠したpipおよびnpmパッケージです。

新しいプラグイン開発(pipおよびnpm)のために、依存関係としてプラグインマネージャーを作成しました。

Pipパッケージ:setup.pyを使用して、プラグインのエントリポイントを追加し、プラグインマネージャ(レジストリ、開始など)で何かを行うことができ ます。https://setuptools.readthedocs.io/en/latest/setuptools .html#automatic-script-creation

npmパッケージ:pipと同様に、インストールを処理するnpmスクリプトにフックがあります。 https://docs.npmjs.com/misc/scripts

私たちのユースケース:

プラグイン開発チームは、コア開発チームから分離されました。プラグイン開発の範囲は、製品の任意のカテゴリで定義されているサードパーティのアプリと統合することです。プラグインインターフェースは次のように分類されています。-ファックス、電話、電子メール... etcプラグインマネージャーを新しいカテゴリに拡張できます。

あなたの場合:多分あなたは1つのプラグインを書いてもらい、ものをするためにそれを再利用することができます。

プラグイン開発者がコアオブジェクトの再利用を使用する必要がある場合、そのオブジェクトは、プラグインがこれらのメソッドを継承できるように、プラグインマネージャ内であるレベルの抽象化を行うことによって使用できます。

製品に実装した方法を共有するだけで、少しのアイデアが得られることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.