복붙노트

[PYTHON] 파이썬에서 최소한의 플러그인 아키텍처 구현하기

PYTHON

파이썬에서 최소한의 플러그인 아키텍처 구현하기

상당히 기술적 인 관객 (과학자)이 사용하는 Python으로 작성된 응용 프로그램이 있습니다.

나는 사용자가 응용 프로그램을 확장 할 수있는 좋은 방법, 즉 스크립팅 / 플러그인 아키텍처를 찾고 있습니다.

나는 아주 가벼운 것을 찾고 있습니다. 대부분의 스크립트 나 플러그인은 제 3 자에 의해 개발되고 배포되지는 않을 것이지만 반복되는 작업을 자동화하고 파일 형식에 대한 지원을 추가하기 위해 사용자가 몇 분 안에 올린 내용 일 것입니다. 그래서 플러그인은 절대 최소의 상용구 코드를 가져야하고, 폴더에 복사하는 것 이외의 '설치'가 필요하지 않습니다. (그래서 setuptools 진입 점이나 Zope 플러그인 아키텍처가 너무 많이 보입니다.)

이미 이와 같은 시스템이 있습니까, 아니면 아이디어 / 영감을 찾아야하는 비슷한 계획을 구현 한 프로젝트가 있습니까?

해결법

  1. ==============================

    1.필자는 기본적으로 "플러그인"이라는 디렉토리를 사용하여 주 앱에서 폴링 한 다음 imp.load_module을 사용하여 파일을 선택하고 모듈 수준의 구성 매개 변수로 잘 알려진 진입 점을 찾은 다음 거기에서 이동할 수 있습니다. 필자는 플러그인이 활성화되어있는 일정량의 동적 효과에 대해 파일 모니터링 기능을 사용하지만 이는 좋은 것입니다.

    필자는 기본적으로 "플러그인"이라는 디렉토리를 사용하여 주 앱에서 폴링 한 다음 imp.load_module을 사용하여 파일을 선택하고 모듈 수준의 구성 매개 변수로 잘 알려진 진입 점을 찾은 다음 거기에서 이동할 수 있습니다. 필자는 플러그인이 활성화되어있는 일정량의 동적 효과에 대해 파일 모니터링 기능을 사용하지만 이는 좋은 것입니다.

    물론, "크고 복잡한 것 X가 필요하지 않다"라는 말을 따라야하는 요구 사항은 한 번에 하나의 발견 된 요구 사항을 다시 구현할 위험이 있습니다. 하지만 그건 당신이 어쨌든 그것을하고 재미 좀 가질 수 없다는 말은 아니지만 :)

  2. ==============================

    2.module_example.py:

    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의 플러그인 시스템이 얼마나 간단한지를 보여줄 것입니다.

    __import__, os.listdir 및 일부 문자열 조작으로 많은 작업을 수행 할 수 있지만 imp 모듈을 조사하고 싶을 수도 있습니다.

  3. ==============================

    3.이 개요에서 기존의 플러그인 프레임 워크 / 라이브러리를 살펴 보시기 바랍니다. 이는 좋은 출발점입니다. 나는 꽤 yapsy를 좋아하지만 그것은 당신의 유스 케이스에 달려있다.

    이 개요에서 기존의 플러그인 프레임 워크 / 라이브러리를 살펴 보시기 바랍니다. 이는 좋은 출발점입니다. 나는 꽤 yapsy를 좋아하지만 그것은 당신의 유스 케이스에 달려있다.

  4. ==============================

    4.그 질문은 정말로 흥미 롭지 만, 나는 더 자세한 내용없이 대답하기가 상당히 어렵다고 생각한다. 어떤 종류의 응용입니까? GUI가 있습니까? 명령 줄 도구입니까? 스크립트 세트? 고유 진입 점이있는 프로그램 등

    그 질문은 정말로 흥미 롭지 만, 나는 더 자세한 내용없이 대답하기가 상당히 어렵다고 생각한다. 어떤 종류의 응용입니까? GUI가 있습니까? 명령 줄 도구입니까? 스크립트 세트? 고유 진입 점이있는 프로그램 등

    내가 가진 작은 정보를 감안할 때 매우 일반적인 방식으로 대답 할 것입니다.

    플러그인을 추가한다는 것은 무슨 뜻입니까?

    순수한 코드 / 설계 연습에서는 사용자가 확장 할 동작 / 특정 동작을 명확하게 결정해야합니다. 항상 덮어 쓰게 될 공통 엔트리 포인트 / 기능 집합을 식별하고 이러한 동작 내에서 그룹을 결정합니다. 이것이 끝나면 응용 프로그램을 쉽게 확장 할 수 있어야합니다.

    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 }
    

    두 방법 모두 확장 기능을 초기화하고 마무리해야 할 수 있습니다. 모든 확장 기능이 구현해야하는 공통 인터페이스를 사용할 수 있습니다 (두 번째 접근 방식에 더 잘 맞습니다. 수은은 모든 확장에 대해 호출되는 reposetup (ui, repo)을 사용합니다). hooks.setup 후크.

    그러나 다시 한 번 더 유용한 답변을 원하면 질문 범위를 좁혀 야합니다.

  5. ==============================

    5.Marty Allchin의 간단한 플러그인 프레임 워크는 내가 필요로하는 기본 라이브러리입니다. 정말 간단하고 쉽게 해킹 할 수있는 무언가를 원한다면 정말 좋은 시작이라고 생각합니다. Django Snippets로도 찾을 수 있습니다.

    Marty Allchin의 간단한 플러그인 프레임 워크는 내가 필요로하는 기본 라이브러리입니다. 정말 간단하고 쉽게 해킹 할 수있는 무언가를 원한다면 정말 좋은 시작이라고 생각합니다. Django Snippets로도 찾을 수 있습니다.

  6. ==============================

    6.나는 디지털 micrograqphs를 다루는 SGI 기계에서 실행되는 이미지 처리 및 분석 패키지 (기술적으로 라이브러리가 아님)를 작성해야한다는 것을 알고 은퇴 한 생물 학자입니다. 나는 C로 코드를 작성하고 스크립팅 언어로 Tcl을 사용했다. GUI는 Tk를 사용하여 완성되었습니다. Tcl에 나타난 명령은 "extensionName commandName arg0 arg1 ... param0 param1 ..."형식이었습니다. 즉, 공백으로 구분 된 간단한 단어와 숫자입니다. Tcl이 "extensionName"하위 문자열을 보았을 때 컨트롤은 C 패키지로 전달되었습니다. 그런 다음 lexer / parser (lex / yacc로 작성)를 통해 명령을 실행 한 다음 필요에 따라 C 루틴을 호출했습니다.

    나는 디지털 micrograqphs를 다루는 SGI 기계에서 실행되는 이미지 처리 및 분석 패키지 (기술적으로 라이브러리가 아님)를 작성해야한다는 것을 알고 은퇴 한 생물 학자입니다. 나는 C로 코드를 작성하고 스크립팅 언어로 Tcl을 사용했다. GUI는 Tk를 사용하여 완성되었습니다. Tcl에 나타난 명령은 "extensionName commandName arg0 arg1 ... param0 param1 ..."형식이었습니다. 즉, 공백으로 구분 된 간단한 단어와 숫자입니다. Tcl이 "extensionName"하위 문자열을 보았을 때 컨트롤은 C 패키지로 전달되었습니다. 그런 다음 lexer / parser (lex / yacc로 작성)를 통해 명령을 실행 한 다음 필요에 따라 C 루틴을 호출했습니다.

    패키지를 운영하는 명령은 GUI의 창을 통해 하나씩 실행될 수 있지만 일괄 작업은 유효한 Tcl 스크립트 인 텍스트 파일을 편집하여 수행되었습니다. 원하는 파일 수준 작업을 수행 한 템플릿을 선택한 다음 실제 디렉터리 및 파일 이름과 패키지 명령을 포함하도록 복사본을 편집합니다. 그것은 매력처럼 작동했습니다. 때까지 ...

    1) 세계가 PC로 변했고 2) Tcl의 조직적 기능이 정말로 불편 해지기 시작하여 약 500 줄 이상의 스크립트가 생겼습니다. 시간이 지났습니다 ...

    나는 은퇴했고 Python은 발명되었고 Tcl의 완벽한 후계자처럼 보였다. 이제는 PC에서 컴파일 (매우 큰) C 프로그램, C 패키지로 파이썬 확장, Python / Gt / Tk에서 GUI를 수행하는 것과 같은 도전에 직면 해본 적이 없기 때문에 지금까지이 포트를 한번도 해보지 않았습니다. ?. 그러나 편집 가능한 템플릿 스크립트를 사용한다는 오래된 생각은 여전히 ​​실행 가능합니다. 또한 네이티브 파이썬 형식으로 패키지 명령을 입력하는 것이 너무 부담스럽지 않아야합니다 (예 :

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

    몇 가지 여분의 점, 괄호 및 쉼표가 있지만 그 표시되지 않습니다.

    파이썬에서 누군가 lex와 yacc 버전을 만들었다는 것을 기억합니다. (시도 : http://www.dabeaz.com/ply/), 그래서 여전히 필요하다면 주위에 있습니다.

    이 말의 핵심은 파이썬 자체가 과학자들이 쓸모있는 "가벼운"프론트 엔드라고 생각한 것입니다. 나는 당신이 왜 그것이 아니라고 생각하는지 궁금합니다. 나는 그 말을 심각하게 의미합니다.

    나중에 추가 : gedit 응용 프로그램은 추가되는 플러그인을 예상하며 사이트에서 몇 분 만에 발견 한 간단한 플러그인 절차에 대한 가장 명확한 설명을 제공합니다. 시험:

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

    나는 아직도 당신의 질문을 더 잘 이해하고 싶습니다. 1) 과학자가 (파이썬) 응용 프로그램을 여러 가지 방법으로 아주 간단하게 사용할 수있게하려면 2) 과학자가 응용 프로그램에 새로운 기능을 추가 할 수있게하려는 지 여부가 명확하지 않습니다. 선택 1은 우리가 이미지에 직면 한 상황이며 순간의 필요성에 맞게 수정 한 일반 스크립트를 사용하도록 유도했습니다. 플러그인의 아이디어로 인도하는 Choice # 2인가, 아니면 명령을 실행 불가능하게 만드는 응용 프로그램의 일부분입니까?

  7. ==============================

    7.Python Decorators를 검색 할 때 간단하면서도 유용한 코드 스 니펫을 발견했습니다. 그것은 당신의 필요에 맞지 않을 수도 있지만 매우 고무적 일 수 있습니다.

    Python Decorators를 검색 할 때 간단하면서도 유용한 코드 스 니펫을 발견했습니다. 그것은 당신의 필요에 맞지 않을 수도 있지만 매우 고무적 일 수 있습니다.

    Scipy 고급 파이썬 # 플러그인 등록 시스템

    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**")
    
  8. ==============================

    8.저는 Pycon 2009에서 Andre Roberge 박사가 제공 한 다양한 플러그인 아키텍처에 대해 좋은 토론을 즐겼습니다. 그는 플러그인을 구현하는 여러 가지 방법에 대해 아주 간단하게 설명합니다.

    저는 Pycon 2009에서 Andre Roberge 박사가 제공 한 다양한 플러그인 아키텍처에 대해 좋은 토론을 즐겼습니다. 그는 플러그인을 구현하는 여러 가지 방법에 대해 아주 간단하게 설명합니다.

    일련의 6 개의 블로그 항목과 함께 Podcast (원숭이 패치에 대한 설명에 이어 두 번째 부분)로 제공됩니다.

    결정을 내리기 전에 빨리 듣는 것이 좋습니다.

  9. ==============================

    9.나는 여기에 도착하여 최소한의 플러그인 아키텍처를 찾았고, 모든 것이 지나치게 과장된 것처럼 보였다. 그래서, 나는 Super Simple Python Plugins을 구현했습니다. 이 파일을 사용하려면 하나 이상의 디렉토리를 만들고 각각에 특별한 __init__.py 파일을 놓습니다. 이러한 디렉토리를 가져 오면 다른 모든 Python 파일이 하위 모듈로로드되고 해당 이름이 __all__ 목록에 배치됩니다. 그런 다음 해당 모듈을 검증 / 초기화 / 등록하는 것은 사용자의 몫입니다. README 파일에 예제가 있습니다.

    나는 여기에 도착하여 최소한의 플러그인 아키텍처를 찾았고, 모든 것이 지나치게 과장된 것처럼 보였다. 그래서, 나는 Super Simple Python Plugins을 구현했습니다. 이 파일을 사용하려면 하나 이상의 디렉토리를 만들고 각각에 특별한 __init__.py 파일을 놓습니다. 이러한 디렉토리를 가져 오면 다른 모든 Python 파일이 하위 모듈로로드되고 해당 이름이 __all__ 목록에 배치됩니다. 그런 다음 해당 모듈을 검증 / 초기화 / 등록하는 것은 사용자의 몫입니다. README 파일에 예제가 있습니다.

  10. ==============================

    10.실제로 setuptools는 프로젝트 설명서에서 가져온 다음 예제와 같이 "plugins directory"와 함께 작동합니다. http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins

    실제로 setuptools는 프로젝트 설명서에서 가져온 다음 예제와 같이 "plugins directory"와 함께 작동합니다. 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는 충돌이나 요구 사항 누락없이 플러그인을로드 할 수 있기 때문에 훨씬 안전한 선택입니다.

    또 다른 이점은 원래의 응용 프로그램이 신경 쓰지 않고 동일한 메커니즘을 사용하여 플러그인 자체를 확장 할 수 있다는 것입니다.

  11. ==============================

    11.플러그인 시스템에 대한 또 다른 접근 방식으로 Extend Me 프로젝트를 확인할 수 있습니다.

    플러그인 시스템에 대한 또 다른 접근 방식으로 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의 새 인스턴스를 만들 때 Python의 다중 상속 덕분에 MyCoolClassExtension과 MyCoolClass의 하위 클래스 인 인스턴스를 모두 가질 수 있습니다.

    클래스 생성을보다 잘 제어하기 위해이 lib에 정의 된 몇 가지 메타 클래스가 있습니다.

    이 lib는 OpenERP Proxy Project에서 사용되며 충분히 잘 작동하는 것 같습니다!

    실제 사용 예를 보려면 OpenERP Proxy '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 DateTime은 확장자입니다.

    확장 기능을 사용하려면 확장 클래스를 포함하는 모듈을 가져오고 기본 클래스에서 확장 클래스를 가짐에 따라 생성 된 모든 Record 객체는 모든 기능을 갖습니다 (위의 경우).

    이 라이브러리의 주요 이점은 확장 가능한 객체를 다루는 코드는 확장에 대해 알 필요가 없으며 확장은 확장 가능한 객체의 모든 것을 바꿀 수 있다는 것입니다.

  12. ==============================

    12.setuptools에는 EntryPoint가 있습니다.

    setuptools에는 EntryPoint가 있습니다.

    AFAIK이 패키지는 pip 또는 virtualenv를 사용하는 경우 항상 사용할 수 있습니다.

  13. ==============================

    13.@ edomaur의 답변을 확장하면 Marty Alchin의 작업에서 영감을 얻은 간단한 플러그인 프레임 워크 인 simple_plugins (뻔뻔한 플러그)를 살펴볼 것을 제안합니다.

    @ 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>
    
  14. ==============================

    14.필자는 Python 용 소형 플러그인 시스템을 찾기 위해 많은 시간을 보냈습니다. 하지만 자연주의적이고 융통성있는 상속 재산이 있다면 그것을 사용하지 않는 것이 좋습니다.

    필자는 Python 용 소형 플러그인 시스템을 찾기 위해 많은 시간을 보냈습니다. 하지만 자연주의적이고 융통성있는 상속 재산이 있다면 그것을 사용하지 않는 것이 좋습니다.

    플러그인 상속을 사용하는 유일한 문제는 가장 구체적인 (상속 트리에서 가장 낮은) 플러그인 클래스가 무엇인지 알지 못한다는 것입니다.

    하지만 이것은 기본 클래스의 상속을 추적하는 metaclass로 해결할 수 있으며, 가장 구체적인 플러그인 (아래 그림의 'Root extended')을 상속받은 클래스를 빌드 할 수 있습니다.

    그래서 저는 그러한 메타 클래스를 코딩하여 해결책을 얻었습니다 :

    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에 참여하십시오.

  15. ==============================

    15.나는 파이썬에서 플러그인 프레임 워크를 검색하는 동안이 스레드를 읽는 데 시간을 보냈다. 나는 약간을 사용했지만 그들과의 결점이 있었다. 다음은 2017 년 인터페이스 조사에서 느슨하게 결합 된 플러그인 관리 시스템 인 귀하의 면밀한 검토를 위해 작성한 것입니다. 나중에로드하십시오. 사용 방법에 대한 자습서입니다.

    나는 파이썬에서 플러그인 프레임 워크를 검색하는 동안이 스레드를 읽는 데 시간을 보냈다. 나는 약간을 사용했지만 그들과의 결점이 있었다. 다음은 2017 년 인터페이스 조사에서 느슨하게 결합 된 플러그인 관리 시스템 인 귀하의 면밀한 검토를 위해 작성한 것입니다. 나중에로드하십시오. 사용 방법에 대한 자습서입니다.

  16. ==============================

    16.pluginlib를 사용할 수 있습니다.

    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"}'))
    
  17. ==============================

    17.Groundwork를 살펴볼 수도 있습니다.

    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
    

    예를 들어 처리 할 고급 패턴도 있습니다. 명령 행 인터페이스, 시그널링 또는 공유 객체.

    기초 작업은 위의 그림과 같이 프로그래밍 방식으로 앱에 바인딩하거나 setuptools를 통해 자동으로 플러그인을 찾습니다. 플러그인이 포함 된 Python 패키지는 특별한 엔트리 포인트 기반을 사용하여 선언해야합니다 .plugin.

    다음은 문서입니다.

    면책 조항 : 저는 Groundwork의 저자 중 한 명입니다.

  18. ==============================

    18.현재 헬스 케어 제품에는 인터페이스 클래스로 구현 된 플러그인 아키텍처가 있습니다. 우리의 기술 스택은 API 용 Python 위에 Django가 있고 frontend 용 nodej 위에 Nuxtjs가 있습니다.

    현재 헬스 케어 제품에는 인터페이스 클래스로 구현 된 플러그인 아키텍처가 있습니다. 우리의 기술 스택은 API 용 Python 위에 Django가 있고 frontend 용 nodej 위에 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

    우리의 유스 케이스 :

    플러그인 개발 팀은 현재 코어 개발 팀과 분리되어 있습니다. 플러그인 개발의 범위는 제품 카테고리 중 하나에 정의 된 타사 앱과의 통합을위한 것입니다. 플러그인 인터페이스는 예를 들면 다음과 같이 분류됩니다 : - 팩스, 전화, 이메일 등 ... 플러그인 관리자는 새로운 카테고리로 향상 될 수 있습니다.

    귀하의 경우 : 어쩌면 당신은 하나의 플러그인을 쓰고 재사용 할 수 있습니다.

    플러그인 개발자가 재사용 핵심 객체를 사용해야하는 경우 해당 객체는 플러그인 관리자 내에서 추상화 수준을 수행하여 사용할 수 있으므로 모든 플러그인이 해당 메소드를 상속받을 수 있습니다.

    우리 제품에 구현 한 방법을 공유하면 조금의 아이디어 만 남을 수 있기를 바랍니다.

  19. from https://stackoverflow.com/questions/932069/building-a-minimal-plugin-architecture-in-python by cc-by-sa and MIT license