Frage

Ich entwickle ein python-framework, das hätte "addons" geschrieben als separate Pakete.I. e.:

import myframework
from myframework.addons import foo, bar

Nun, was ich versuche zu ordnen ist, so dass diese addons können verteilt werden getrennt von Kern-framework und injiziert in myframework.addons namespace.

Derzeit ist meine beste Lösung für dieses Problem ist die folgende.Ein add-on bereitgestellt wird (wahrscheinlich in {python_version}/site-packages/ wie so:

fooext/
fooext/__init__.py
fooext/myframework/
fooext/myframework/__init__.py
fooext/myframework/addons/
fooext/myframework/addons/__init__.py
fooext/myframework/addons/foo.py

Die fooext/myframework/addons/__init__.py hätte die pkgutil-Pfad-Erweiterung code:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)

Das problem ist, dass für diese arbeiten, die PYTHONPATH haben muss fooext/ in es, aber die einzige Sache, die es haben würde, ist das übergeordnete Installationsverzeichnis (in der Regel die oben genannten site-packages).

Die Lösung ist, haben extra code in myframework/addons/__init__.py die würde tranverse sys.path und schauen Sie für alle Module mit einer myframework sub-Paket-in diesem Fall fügt es hinzu sys.path und alles funktioniert.

Eine andere Idee ist, hatte ich zu schreiben die addon-Dateien direkt zu myframework/addons/ installieren Position, aber dann wäre es um die Entwicklung und Bereitstellung namespace unterscheiden.

Gibt es einen besseren Weg, dies zu erreichen-oder vielleicht einen anderen Ansatz, um die oben genannten Verteilungs-problem insgesamt?

War es hilfreich?

Lösung

Gibt es einen besseren Weg, dies zu erreichen-oder vielleicht einen anderen Ansatz, um die oben genannten Verteilungs-problem insgesamt?

Evtl.Python-Modul/Paket-setup ist in der Regel schwierig zu manipulieren dynamisch wie dieses, aber seine Objekt/Klasse system offen und erweiterbar und in einer gut definierten Weise.Wenn Sie Module und Pakete, die nicht ganz die Funktionen, die Sie benötigen, um Kapseln Ihr Projekt schön Sie verwenden können Klassen statt.

Sie könnten zum Beispiel die Erweiterung der Funktionalität in ein komplett anderes Paket, aber lassen Sie es injizieren Klassen in Ihrer Grundstruktur durch eine bestimmte Schnittstelle.zB.myframework/__init__.py mit einem basic-Anwendung-wrapper:

class MyFramework(object):
    """A bare MyFramework, I only hold a person's name
    """
    _addons= {}
    @staticmethod
    def addAddon(name, addon):
        MyFramework._addons[name]= addon

    def __init__(self, person):
        self.person= person
        for name, addon in MyFramework._addons.items():
            setattr(self, name, addon(self))

Dann Sie könnte haben die Erweiterung der Funktionalität in einem myexts/helloer.py,, die hält eine Referenz auf seinen 'Besitzer' oder 'äußeren' MyFramework Instanz der Klasse:

class Helloer(object):
    def __init__(self, owner):
        self.owner= owner
    def hello(self):
        print 'hello '+self.owner.person

import myframework
myframework.MyFramework.addAddon('helloer', Helloer)

So, jetzt, wenn Sie nur die "importieren myframework", erhalten Sie nur die grundlegenden Funktionen.Aber wenn Sie auch "importieren myexts.helloer" Sie erhalten auch die Möglichkeit zu nennen, MyFramework.helloer.Hallo().Natürlich können Sie auch definieren Protokolle für addons, die die Interaktion mit der die Rahmenbedingungen Verhalten, und jeder andere.Sie können auch Dinge tun, wie innere Klassen eine Unterklasse des Frameworks außer Kraft setzen können anpassen die zimmerreserviereung, ohne das Affen-patch-Klassen, die auf andere Anwendungen auswirken kann, wenn Sie Sie brauchen, das Niveau der Komplexität.

Encapsulating Verhalten wie diese können nützlich sein, aber es ist normalerweise nervig arbeiten zur Anpassung Modul-level-code, den Sie bereits zu diesem Modell passen.

Andere Tipps

Setuptools hat die Fähigkeit, lookup-Paket "entry points" (Funktionen, Objekte, was auch immer) mit Namen.Trac verwendet diesen Mechanismus, um laden Sie Ihre plugins, und es funktioniert gut.

Es ist ein völlig neues setup für namespaces.Haben Sie einen Blick auf Packaging namespace packages.Kurz gesagt, Sie haben drei Optionen auf der Grundlage, wie viel abwärtskompatibel Sie möchten, dass Ihre code.Es ist auch eine relevante PEP, der ersetzt den bereits in anderen Antworten: PEP 420.

Es klingt wie, was Sie nach vollbracht werden kann, ganz ordentlich mit import-Haken.

Dies ist eine Möglichkeit, das schreiben von benutzerdefiniertem code laden, die können werden verbunden mit einem Paket (oder in Ihrem Fall eine Rahmen), um die Belastung aller sub-Pakete und Module, anders als python ' s Standard loading mechanism.Dann können Sie installieren die loader in site-Paketen wie Basis-Paket oder unter dem Rahmen.

Wenn ein Paket ist gefunden zu werden verbunden mit die loader (kann einfach hart kodiert werden, um den relativen Pfad, falls erforderlich), wird es immer dann verwenden Sie den Lader zu laden alle add-ons, zum Beispiel.Dies hat den Vorteil, nicht erfordern hantieren von den PYTHONPATH, die in der Regel lohnt sich so kurz wie möglich.

Die alternative dazu ist die Verwendung der init Dateien umleiten der import-Aufruf für ein sub-Modul an die, die Sie wollen, es zu Holen, aber dieses ist ein bisschen chaotisch.

Mehr Informationen zum import-Haken finden Sie hier:

http://www.python.org/dev/peps/pep-0302/

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top