Mam aplikację napisaną w języku Python, która jest używana przez dość technicznych odbiorców (naukowców).
Szukam dobrego sposobu na rozszerzenie aplikacji przez użytkowników, tj. Architekturę skryptów / wtyczek.
Szukam czegoś wyjątkowo lekkiego . Większość skryptów lub wtyczek nie będzie opracowywana i dystrybuowana przez firmę zewnętrzną i instalowana, ale za kilka minut zostanie wymyślona przez użytkownika w celu zautomatyzowania powtarzającego się zadania, dodania obsługi formatu pliku, itd. Tak więc wtyczki powinny mieć absolutnie minimalny kod typu „kocioł” i nie wymagają „instalacji” innej niż kopiowanie do folderu (więc coś w rodzaju punktów wejścia do setuptools lub architektura wtyczek Zope wydaje się zbyt duża).
Czy istnieją już takie systemy lub projekty, które wdrażają podobny schemat, na który powinienem szukać pomysłów / inspiracji?
imp
Moduł jest zastąpionaimportlib
począwszy od Pythona 3.4imp.load_module
.module_example.py
:loader.py
:Z pewnością jest „minimalny”, absolutnie nie ma sprawdzania błędów, prawdopodobnie niezliczone problemy bezpieczeństwa, nie jest zbyt elastyczny - ale powinien pokazać, jak prosty może być system wtyczek w Pythonie ..
Prawdopodobnie chcesz zajrzeć do imp modułu też, choć można zrobić wiele z zaledwie
__import__
,os.listdir
a niektóre łańcuchach.źródło
def call_plugin(name, *args)
nadef call_plugin(name, *args, **kwargs)
, a następnieplugin.plugin_main(*args)
doplugin.plugin_main(*args, **kwargs)
imp
jest przestarzały na korzyśćimportlib
Spójrz na ten przegląd istniejących frameworków / bibliotek wtyczek , jest to dobry punkt wyjścia. Bardzo lubię yapsy , ale to zależy od twojego przypadku użycia.
źródło
Chociaż to pytanie jest naprawdę interesujące, myślę, że trudno jest odpowiedzieć bez dodatkowych szczegółów. Co to za aplikacja? Czy ma GUI? Czy to narzędzie wiersza polecenia? Zestaw skryptów? Program z unikalnym punktem wejścia itp.
Biorąc pod uwagę niewiele informacji, które posiadam, odpowiem w bardzo ogólny sposób.
Co oznacza, że musisz dodać wtyczki?
W praktyce opartej na czystym kodzie / projektowaniu musisz jasno określić, jakie zachowania / konkretne działania chcesz rozszerzyć od użytkowników. Zidentyfikuj wspólny punkt wejścia / zestaw funkcji, które zawsze zostaną zastąpione, i określ grupy w ramach tych działań. Po wykonaniu tej czynności rozszerzenie aplikacji powinno być łatwe,
Przykład użycia hooków , zainspirowanych MediaWiki (PHP, ale czy język naprawdę ma znaczenie?):
Kolejny przykład, inspirowany rtęcią. W tym przypadku rozszerzenia dodają tylko polecenia do pliku wykonywalnego wiersza polecenia hg , przedłużając zachowanie.
W przypadku obu podejść może być konieczne wspólne zainicjowanie i zakończenie rozszerzenia. Możesz albo użyć wspólnego interfejsu, który wszystkie rozszerzenia będą musiały zaimplementować (lepiej pasuje do drugiego podejścia; mercurial używa reposetup (interfejsu użytkownika, repo), który jest wywoływany dla wszystkich rozszerzeń), lub zastosować podejście typu hook, z hooks.setup hook.
Ale znowu, jeśli chcesz bardziej przydatnych odpowiedzi, musisz zawęzić swoje pytanie;)
źródło
Prosta struktura wtyczek Marty'ego Allchina jest bazą, której używam do własnych potrzeb. Naprawdę polecam przyjrzeć się temu, myślę, że to naprawdę dobry początek, jeśli chcesz czegoś prostego i łatwego do włamania. Możesz go również znaleźć jako fragmenty Django .
źródło
Jestem emerytowanym biologiem, który zajmował się cyfrowymi mikrografami i stwierdził, że musi napisać pakiet do przetwarzania obrazu i analizy (nie technicznie biblioteki), aby uruchomić go na maszynie SGi. Napisałem kod w C i użyłem Tcl jako języka skryptowego. GUI, tak jak było, zostało wykonane przy użyciu Tk. Polecenia, które pojawiły się w Tcl, miały postać „rozszerzenieNazwa nazwa polecenia arg0 arg1 ... param0 param1 ...”, to znaczy proste słowa i liczby oddzielone spacjami. Gdy Tcl zobaczył podciąg „extensionName”, kontrola została przekazana do pakietu C. To z kolei uruchomiło polecenie przez lexer / parser (wykonane w lex / yacc), a następnie w razie potrzeby wywołało procedury C.
Polecenia do obsługi pakietu można uruchamiać pojedynczo za pośrednictwem okna w graficznym interfejsie użytkownika, ale zadania wsadowe były wykonywane przez edycję plików tekstowych, które były poprawnymi skryptami Tcl; wybrałeś szablon, który wykonał rodzaj operacji na poziomie pliku, którą chcesz wykonać, a następnie edytowałeś kopię, aby zawierała rzeczywisty katalog i nazwy plików oraz polecenia pakietu. Działa jak urok. Aż do ...
1) Świat zwrócił się ku komputerom PC i 2) skrypty wydłużyły się do około 500 linii, gdy słabe możliwości organizacyjne Tcl stały się prawdziwą niedogodnością. Czas minął ...
Przeszedłem na emeryturę, wymyśliłem Pythona i wyglądało to na idealnego następcę Tcl. Teraz nigdy nie robiłem portu, ponieważ nigdy nie stawiałem czoła wyzwaniom kompilacji (dość dużych) programów C na PC, rozszerzania Pythona za pomocą pakietu C i robienia GUI w Pythonie / Gt? / Tk? /? ? Jednak stary pomysł posiadania edytowalnych skryptów szablonów nadal wydaje się praktyczny. Ponadto nie powinno być zbyt wielkim obciążeniem wprowadzanie poleceń pakietu w natywnej formie Pythona, np .:
pakietName.command (arg0, arg1, ..., param0, param1, ...)
Kilka dodatkowych kropek, parenów i przecinków, ale to nie są wisiorki.
Pamiętam, że ktoś napisał wersje lex i yacc w Pythonie (spróbuj: http://www.dabeaz.com/ply/ ), więc jeśli są one nadal potrzebne, są w pobliżu.
Chodzi mi o to, że wydawało mi się, że sam Python JEST pożądanym „lekkim” frontem używanym przez naukowców. Jestem ciekawy, dlaczego uważasz, że tak nie jest, i mam na myśli to poważnie.
dodane później: Aplikacja gedit przewiduje dodawanie wtyczek, a ich witryna zawiera wyjaśnienie prostej procedury wtyczek, którą znalazłem w ciągu kilku minut rozglądania się. Próbować:
https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld
Nadal chciałbym lepiej zrozumieć twoje pytanie. Nie jestem pewien, czy 1) chcesz, aby naukowcy mogli korzystać z twojej aplikacji (Python) po prostu na różne sposoby, czy 2) chcesz, aby naukowcy mogli dodawać nowe możliwości do twojej aplikacji. Wybór nr 1 to sytuacja, w której mieliśmy do czynienia z obrazami, i to doprowadziło nas do użycia ogólnych skryptów, które zmodyfikowaliśmy, aby dopasować do potrzeb chwili. Czy to Choice # 2 prowadzi do idei wtyczek, czy jest to jakiś aspekt twojej aplikacji, który sprawia, że wydawanie poleceń jest niewykonalne?
źródło
Podczas wyszukiwania Dekoratorów Pythona znalazłem prosty, ale przydatny fragment kodu. To może nie pasować do twoich potrzeb, ale bardzo inspirujące.
Scipy Advanced Python # Plugin System rejestracji
Stosowanie:
źródło
WordProcessor.plugin
nic nie zwraca (None
), więcCleanMdashesExtension
później importowanie klasy jest po prostu importemNone
. Jeśli klasy wtyczek są przydatne same w sobie, utwórz.plugin
metodę classreturn plugin
.Podobała mi się miła dyskusja na temat różnych architektur wtyczek wygłoszona przez dr Andre Roberge na Pycon 2009. Daje dobry przegląd różnych sposobów implementacji wtyczek, zaczynając od czegoś naprawdę prostego.
Jest dostępny jako podcast (druga część po wyjaśnieniu łatania małp) wraz z serią sześciu wpisów na blogu .
Zalecam szybkie posłuchanie, zanim podejmiesz decyzję.
źródło
Przybyłem tutaj, szukając minimalnej architektury wtyczek i znalazłem wiele rzeczy, które wydawały mi się przesadne. Wdrożyłem więc Super Simple Python Plugins . Aby z niego skorzystać, tworzysz jeden lub więcej katalogów i upuszczasz specjalny
__init__.py
plik w każdym z nich. Zaimportowanie tych katalogów spowoduje, że wszystkie inne pliki Pythona zostaną załadowane jako podmoduły, a ich nazwy zostaną umieszczone na__all__
liście. Następnie do ciebie należy sprawdzenie / zainicjowanie / rejestracja tych modułów. W pliku README jest przykład.źródło
W rzeczywistości setuptools działa z „katalogiem wtyczek”, jak w poniższym przykładzie z dokumentacji projektu: http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins
Przykładowe użycie:
W dłuższej perspektywie setuptools jest znacznie bezpieczniejszym wyborem, ponieważ może ładować wtyczki bez konfliktów i brakujących wymagań.
Kolejną zaletą jest to, że same wtyczki można rozszerzyć przy użyciu tego samego mechanizmu, bez konieczności dbania o to przez oryginalne aplikacje.
źródło
Jako wzajemne podejście do systemu wtyczek możesz sprawdzić projekt Extend Me .
Na przykład zdefiniujmy prostą klasę i jej rozszerzenie
I spróbuj użyć:
I pokaż, co kryje się za sceną:
biblioteka ext_me manipuluje procesem tworzenia klas za pomocą metaklas, dlatego w powyższym przykładzie podczas tworzenia nowej instancji
MyCoolClass
otrzymaliśmy instancję nowej klasy, która jest podklasą obuMyCoolClassExtension
iMyCoolClass
ma funkcjonalność obu z nich, dzięki wielokrotnemu dziedziczeniu PythonaAby uzyskać lepszą kontrolę nad tworzeniem klas, w tej bibliotece zdefiniowano kilka metaklas:
ExtensibleType
- umożliwia prostą rozszerzalność poprzez podklasowanieExtensibleByHashType
- podobny do ExtensibleType, ale posiadający zdolność do budowania wyspecjalizowanych wersji klasy, umożliwiający globalne rozszerzenie klasy podstawowej i rozszerzenie specjalistycznych wersji klasyTa biblioteka jest używana w OpenERP Proxy Project i wydaje się, że działa wystarczająco dobrze!
Prawdziwy przykład użycia znajduje się w rozszerzeniu OpenERP Proxy „field_datetime” :
Record
tutaj jest obiekt rozciągliwy.RecordDateTime
jest rozszerzeniem.Aby włączyć rozszerzenie, wystarczy zaimportować moduł zawierający klasę rozszerzenia i (w powyższym przypadku) wszystkie
Record
obiekty utworzone po nim będą miały klasę rozszerzenia w klasach podstawowych, a tym samym będą mieć całą swoją funkcjonalność.Główną zaletą tej biblioteki jest to, że kod obsługujący obiekty rozszerzalne nie musi wiedzieć o rozszerzeniu, a rozszerzenia mogą zmieniać wszystko w obiektach rozszerzalnych.
źródło
my_cool_obj = MyCoolClassExtension1()
Zamiastmy_cool_obj = MyCoolClass()
__new__
metodę, więc automatycznie wyszukuje wszystkie podklasy i buduje nową klasę, czyli podklasę wszystkich z nich, i powraca nowa instancja tej utworzonej klasy. Dlatego oryginalna aplikacja nie musi wiedzieć o wszystkich rozszerzeniach. takie podejście jest przydatne podczas budowania biblioteki, aby użytkownik końcowy mógł łatwo modyfikować lub rozszerzać swoje zachowanie. w powyższym przykładzie MyCoolClass może być zdefiniowany w bibliotece i przez niego używany, a MyCoolClassExtension może być zdefiniowany przez użytkownika końcowego.setuptools ma EntryPoint :
AFAIK ten pakiet jest zawsze dostępny, jeśli używasz pip lub virtualenv.
źródło
Rozwijając odpowiedź @ edomaura, mogę zasugerować przyjrzenie się simple_plugins (bezwstydnej wtyczce), która jest prostym frameworkiem wtyczek zainspirowanym pracą Marty'ego Alchina .
Krótki przykład użycia na podstawie README projektu:
źródło
Spędziłem czas czytając ten wątek, gdy szukałem frameworka w Pythonie od czasu do czasu. Mam stosowane niektóre, ale nie było niedociągnięć z nich. Oto, co wymyślę do Twojej analizy w 2017 roku, wolny od interfejsu, luźno powiązany system zarządzania wtyczkami: Załaduj mnie później . Oto samouczki, jak z niego korzystać.
źródło
Możesz użyć pluginlib .
Wtyczki można łatwo tworzyć i można je ładować z innych pakietów, ścieżek plików lub punktów wejścia.
Utwórz klasę nadrzędną wtyczki, definiując wszelkie wymagane metody:
Utwórz wtyczkę, dziedzicząc klasę nadrzędną:
Załaduj wtyczki:
źródło
foo
możesz mieć moduł o nazwie, wfoo.parents
którym definiujesz klasy nadrzędne. Następnie wtyczki zostaną zaimportowanefoo.parents
. Działa to dobrze w większości przypadków użycia. Ponieważ samo „foo” również jest importowane, aby uniknąć możliwości importowania cyklicznego, wiele projektów pozostawia katalog główny modułu pusty i używa__main__.py
pliku lub punktów wejścia do uruchomienia aplikacji.Spędziłem dużo czasu próbując znaleźć mały system wtyczek dla Pythona, który pasowałby do moich potrzeb. Ale potem pomyślałem, że jeśli jest już dziedzictwo, które jest naturalne i elastyczne, dlaczego go nie użyć.
Jedynym problemem związanym z używaniem dziedziczenia dla wtyczek jest to, że nie wiesz, jakie są najbardziej szczegółowe (najniższe na drzewie dziedziczenia) klasy wtyczek.
Można to jednak rozwiązać za pomocą metaklasy, która śledzi dziedziczenie klasy podstawowej, i ewentualnie mogłaby zbudować klasę, która dziedziczy z najbardziej określonych wtyczek („Root extension” na poniższym rysunku)
Więc znalazłem rozwiązanie, kodując taką metaklasę:
Więc jeśli masz bazę Root wykonaną z metaklasy i masz drzewo wtyczek, które z niej dziedziczą, możesz automatycznie uzyskać klasę, która dziedziczy z najbardziej specyficznych wtyczek po prostu poprzez podklasowanie:
Baza kodu jest dość mała (~ 30 linii czystego kodu) i tak elastyczna, jak pozwala na to dziedziczenie.
Jeśli jesteś zainteresowany, zaangażuj się @ https://github.com/thodnev/pluginlib
źródło
Możesz także rzucić okiem na Groundwork .
Chodzi o to, aby budować aplikacje wokół komponentów wielokrotnego użytku, zwanych wzorcami i wtyczkami. Wtyczki są klasami, które pochodzą
GwBasePattern
. Oto podstawowy przykład:Istnieją również bardziej zaawansowane wzorce do obsługi np. Interfejsów linii poleceń, sygnalizacji lub współdzielonych obiektów.
Groundwork znajduje wtyczki albo programowo, wiążąc je z aplikacją, jak pokazano powyżej, lub automatycznie za pośrednictwem
setuptools
. Pakiety Python zawierające wtyczki muszą je deklarować przy użyciu specjalnego punktu wejściagroundwork.plugin
.Oto dokumenty .
Uwaga : Jestem jednym z autorów Groundwork.
źródło
W naszym obecnym produkcie opieki zdrowotnej mamy architekturę wtyczek zaimplementowaną z klasą interfejsu. Nasz stos technologii to Django na Pythonie dla API i Nuxtjs na nodejs dla frontendu.
Mamy aplikację menedżera wtyczek napisaną dla naszego produktu, która jest w zasadzie pakietem pip i npm, zgodnym z Django i Nuxtjs.
Do tworzenia nowych wtyczek (pip i npm) stworzyliśmy menedżera wtyczek jako zależność.
W pakiecie Pip: Za pomocą setup.py możesz dodać punkt wejścia wtyczki, aby zrobić coś z menedżerem wtyczek (rejestr, inicjacje, ... itp.) Https://setuptools.readthedocs.io/en/latest/setuptools .html # automatyczne tworzenie skryptów
W pakiecie npm: Podobnie do pipa, w skryptach npm znajdują się haki do obsługi instalacji. https://docs.npmjs.com/misc/scripts
Nasz przypadek użycia:
zespół programistów wtyczek jest teraz niezależny od zespołu programistów. Opracowywanie wtyczek ma na celu integrację z aplikacjami innych firm, które są zdefiniowane w dowolnej kategorii produktu. Interfejsy wtyczek są podzielone na następujące kategorie: - Faks, telefon, e-mail ... itd. Menedżer wtyczek można rozszerzyć o nowe kategorie.
W twoim przypadku: Może możesz napisać jedną wtyczkę i użyć jej ponownie do robienia rzeczy.
Jeśli twórcy wtyczek muszą użyć ponownie podstawowych obiektów, obiekt ten może zostać wykorzystany poprzez wykonanie poziomu abstrakcji w menedżerze wtyczek, aby wszelkie wtyczki mogły odziedziczyć te metody.
Po prostu dzieląc się tym, jak wdrożyliśmy nasz produkt, mamy nadzieję, że da to mały pomysł.
źródło