Ganz einfache Frage: Kann ich ein bestimmtes Modul in den "Import Namespace" einfügen? Also, das ein anderes Modul dieses Modul beim Versuch des Imports findet, ohne das ich sys.path verändere?
Hintergrund ist mein Plugin System. Jedes Plugin sollte eine Klasse enthalten können, die von einer Basisklasse abgeleitet ist. Diese Basisklasse möchte ich natürlich ungern direkt zu den Plugins schieben, da sie selbst alles nötige implementieren sollte, um für den Rest des Programmes benutzbar zu sein, und man bei jedem Plugin natürlich vom Engine-Code separiert arbeitet. Zu sys.path hinzufügen, kurz bevor mein Plugin System das Modul importiert, möchte ich auch ungerne, da das einen Zugriff auf ~50% der Engine Funktionalitäten erlauben würde und zugleich fehleranfällig wäre (Sich ändernde Paths, beschränkt auf den Path des Plugin Systems, etc.).
Import Namespace
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Du kannst die Umgebungsvariable ``PYTHONPATH`` verwenden, aber sonderlich toll ist das auch nicht. Vielleicht reicht dir ja ein Import-Hook?
Übrigens muss ich sagen, dass deine Einwände ``sys.path`` zu erweitern mich eigentlich nicht überzeugen.
Übrigens muss ich sagen, dass deine Einwände ``sys.path`` zu erweitern mich eigentlich nicht überzeugen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Nun, würde ich sys.path verändern, müsste ich erstmal den Pfad, in dem das Modul liegt, herausfinden. Ginge das über os.path.dirname(__file__)? Und ist das garantiert? Bisher erschien mir __file__ manchmal mit Pfadangabe, manchmal ohne. Ansonsten habe ich in os.path nichts gefunden (und os.getcwd fällt wohl flach).
Wenn das garantiert wäre, könnte ich sys.path verwenden, und würde es wohl auch tun.
Import-Hook:
Kann ich (noch) nichts mit anfangen, werde mal danach suchen.
Wenn das garantiert wäre, könnte ich sys.path verwenden, und würde es wohl auch tun.
Import-Hook:
Kann ich (noch) nichts mit anfangen, werde mal danach suchen.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Den Pfad herauszufinden hat bei mir eigentlich immer funktioniert, siehe wie das Plugin System von What's On Air das macht.str1442 hat geschrieben:Nun, würde ich sys.path verändern, müsste ich erstmal den Pfad, in dem das Modul liegt, herausfinden. Ginge das über os.path.dirname(__file__)? Und ist das garantiert? Bisher erschien mir __file__ manchmal mit Pfadangabe, manchmal ohne.
Eine andere Idee für Plugins weren die setuptools-Entrypoints. Damit habe ich selbst noch nichts gemacht, weil es damals(TM) noch keine setuptools gab.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Das bisherige Plugin System (nur der Import Teil) sieht so aus:
und funktioniert, wobei die einzelnen Plugins und deren Namen + Pfade in einer CSV Datei verwaltet werden.
Ich habe mir What's on Air mal angeschaut, und da wird os.path.dirname(__file__) ja auch verwendet, wird wohl also funktionieren, wenn ich das noch in gescheid' kapsele. Danke für die Hilfe.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import with_statement
import imp
DESCRIPTION = (r".py", r"U", imp.PY_SOURCE)
ALL = []
def load_plugin(name, full_path):
with open(full_path, DESCRIPTION[1]) as file_obj:
imp.acquire_lock()
try:
new_plugin_module = imp.load_module(name, file_obj,
full_path,
DESCRIPTION)
finally:
imp.release_lock()
ALL.append(new_plugin_module)
return new_plugin_module
Ich habe mir What's on Air mal angeschaut, und da wird os.path.dirname(__file__) ja auch verwendet, wird wohl also funktionieren, wenn ich das noch in gescheid' kapsele. Danke für die Hilfe.
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hallo str!str1442 hat geschrieben:Ginge das über os.path.dirname(__file__)? Und ist das garantiert?
Natürlich geht das damit. Allerdings musst du zusätzlich ``os.path.abspath()`` mitverwenden um plattformübergreifend, garantiert den Pfad zurück zu erhalten.
Code: Alles auswählen
os.path.dirname(os.path.abspath(__file__))
Code: Alles auswählen
APPDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, APPDIR)
Gerold
PS: http://www.python-forum.de/post-64471.html#64471
.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Meinst du vielleicht sowas..str1442 hat geschrieben:Ganz einfache Frage: Kann ich ein bestimmtes Modul in den "Import Namespace" einfügen? Also, das ein anderes Modul dieses Modul beim Versuch des Imports findet, ohne das ich sys.path verändere?
Code: Alles auswählen
from __future__ import with_statement
import sys,imp
class Plugins(object):
__full_path ='C:\\Users\\Qubit\\pytest\\'
__modules = set()
DESCRIPTION = (r".py", r"U", imp.PY_SOURCE)
ALL=[]
@classmethod
def add(cls, mod_name):
cls.__modules.add(mod_name)
def find_module(self, mod_name, package_path):
if package_path: return
if mod_name in self.__modules: return self
def load_module(self, mod_name):
file_name = self.__full_path+'Plugins_'+mod_name+'.py'
with open(file_name, self.DESCRIPTION[1]) as file_obj:
imp.acquire_lock()
try:
plugin_module = imp.load_module(mod_name, file_obj,
file_name,
self.DESCRIPTION)
finally:
imp.release_lock()
self.ALL.append(plugin_module)
print "Imported:", mod_name
return plugin_module
sys.meta_path.append(Plugins())
Plugins.add("Test")
>>> dir()
['Plugins', '__builtins__', '__doc__', '__name__', 'imp', 'sys', 'with_statement']
>>> from Test import Test
Imported: Test
>>> dir()
['Plugins', 'Test', '__builtins__', '__doc__', '__name__', 'imp', 'sys', 'with_statement']
>>> Test.me()
Hello, Plugins_Test
>>> 'C:\\Users\\Qubit\\pytest' in sys.path
False
>>>
@gerold:
Danke für die Erläuterungen! Ich war mir nur nicht ganz sicher, da __file__ ja nicht unbedingt auf "path" hindeutet, und ich einmal __file__ einmal mit und einmal ohne path gesehen habe.
@Qubit:
Nein, ich meinte es eigentlich genau andersrum .
Also das ein Plugin, das mithilfe des Plugin Systems importiert werden soll, per "import xyz" xyz importieren kann, obwohl der Pfad von xyz nicht in sys.path ist (also auch nicht "." ist).
Ich werde aber nun wohl doch den Weg über sys.path gehen, ich muss nur noch sehen, ob ich eine Art "importable_from_plugins" Directory anlege, und dort "dummy Module" reinlege, oder direkt auf das richtige Package verlinke, je nachdem, was besser gekapselt und sauber wirkt.
Jetzt schaue ich mir noch sys.meta_path an .
Danke für die Erläuterungen! Ich war mir nur nicht ganz sicher, da __file__ ja nicht unbedingt auf "path" hindeutet, und ich einmal __file__ einmal mit und einmal ohne path gesehen habe.
@Qubit:
Nein, ich meinte es eigentlich genau andersrum .
Also das ein Plugin, das mithilfe des Plugin Systems importiert werden soll, per "import xyz" xyz importieren kann, obwohl der Pfad von xyz nicht in sys.path ist (also auch nicht "." ist).
Ich werde aber nun wohl doch den Weg über sys.path gehen, ich muss nur noch sehen, ob ich eine Art "importable_from_plugins" Directory anlege, und dort "dummy Module" reinlege, oder direkt auf das richtige Package verlinke, je nachdem, was besser gekapselt und sauber wirkt.
Jetzt schaue ich mir noch sys.meta_path an .
In der Doku steht dazu nichtsJetzt schaue ich mir noch sys.meta_path an
EDIT:
Stand in "Whats new in Py 2.3", wobei dabei nicht stand, wie genau die Objekte "traversiert" werden.sys.meta_path is a list of importer objects that will be traversed before sys.path is checked. This list is initially empty, but user code can add objects to it. Additional built-in and frozen modules can be imported by an object added to this list.
Da das hier so gut reinpasst:
Man kann auch selbst ein Modul bereitstellen per sys.modules. Man könnte zb sowas machen:
Bei einem import wird dieses Modul dann immer gefunden. Eine andere Möglichkeit ist, die "Plugin" Klasse dem "builtins" Modul hinzuzufügen, wodurch man immer Zugriff darauf hat.
Das sind aber mehr oder weniger Hacks, die man vermeiden sollte - zumindest zweiteres ist das definitiv. Die erste Möglichkeit ist imho grenzwertig.
Man kann auch selbst ein Modul bereitstellen per sys.modules. Man könnte zb sowas machen:
Code: Alles auswählen
import sys
from types import ModuleType
plugin_mod = ModuleType("imaginary_plugin")
plugin_mod.Plugin = <Plugin Klasse>
sys.modules[plugin_mod.__name__] = plugin_mod
Das sind aber mehr oder weniger Hacks, die man vermeiden sollte - zumindest zweiteres ist das definitiv. Die erste Möglichkeit ist imho grenzwertig.