Seite 1 von 1
importieren von Modulen aus Package
Verfasst: Donnerstag 8. Mai 2008, 15:57
von Jan-Peer
Hallo,
ich stehe ein wenig auf dem Schlauch: Die entsprechenden .py Dateien und die __init__.py liegen im Unterverzeichnis tests. Trotzdem scheint hier was gehörig falsch zu laufen:
Code: Alles auswählen
>>> m1 = __import__('tests.test_couponconfig')
>>> m2 = __import__('tests.test_couponalchemist')
>>> m3 = __import__('tests.test_couponconfig', globals, locals)
>>> m1 == m2
True
>>> m1 == m3
True
>>>
Hintergrund ist, daß ich fürs unittesting ein Unterverzeichnis 'tests' angelegt habe, in dem ich alle Testcases nach Modulen sortiert ablege. Im Hauptverzeichnis liegt das folgende Skript, mit dem die TCs dann abgearbeitet werden sollen:
Code: Alles auswählen
import unittest
modules_to_test = (
'tests.test_couponconfig',
'tests.test_couponalchemist'
)
def suite():
tloader = unittest.defaultTestLoader
alltests = unittest.TestSuite()
for module in map(__import__, modules_to_test):
alltests.addTest(tloader.loadTestsFromModule(module))
return alltests
if __name__ == "__main__":
unittest.main(defaultTest="suite")
Wer kann mir weiterhelfen?
Verfasst: Donnerstag 8. Mai 2008, 18:03
von Trundle
__import__.__doc__ hat geschrieben:When importing a module from a package, note that __import__('A.B', ...) returns package A when fromlist is empty, but its submodule B when fromlist is not empty.
Ist also beabsichtigtes, dokumentiertes Verhalten und es läuft nichts falsch.
Verfasst: Donnerstag 8. Mai 2008, 18:13
von Jan-Peer
Danke

Verfasst: Donnerstag 8. Mai 2008, 18:38
von mitsuhiko
globals und locals sind Funktionen. Wenn, dann musst du die Aufrufen bevor du sie __import__ übergibst.
Für dynamisches Importieren stellt Werkzeug was schickes bereit, das kannst du dir kopieren:
http://dev.pocoo.org/projects/werkzeug/ ... 445c#L1535
Dann einfach
Code: Alles auswählen
>>> import_string("cgi")
<module 'cgi' from '/opt/local/lib/python2.5/cgi.pyc'>
>>> import_string("cgi.escape")
<function escape at 0x11f6f30>
>>> import_string("xml.sax.saxutils.escape")
<function escape at 0x135f8f0>
Verfasst: Freitag 9. Mai 2008, 00:17
von Leonidas
Ja, sowas wünsche ich mir öfters statt __import__. Die Parameter die es nimmt und die Art und Weise wie es aufgerufen werden will ist beim besten Willen nicht intuitiv.
Verfasst: Freitag 9. Mai 2008, 08:20
von jens
Jep, Die API von __import__ ist grauenhaft

Verfasst: Freitag 9. Mai 2008, 20:22
von birkenfeld
Leonidas hat geschrieben:Ja, sowas wünsche ich mir öfters statt __import__. Die Parameter die es nimmt und die Art und Weise wie es aufgerufen werden will ist beim besten Willen nicht intuitiv.
Nun ja, zum einen hat es diese Unterstriche, und zum anderen wird diese Funktion für jeden Import aufgerufen -- man will also, dass sie möglichst schnell und effektiv ist, und nicht, dass sie möglichst viel Komfort bietet.
Verfasst: Freitag 9. Mai 2008, 21:11
von Leonidas
birkenfeld hat geschrieben:Nun ja, zum einen hat es diese Unterstriche, und zum anderen wird diese Funktion für jeden Import aufgerufen -- man will also, dass sie möglichst schnell und effektiv ist, und nicht, dass sie möglichst viel Komfort bietet.
Natürlich, es ist mir nicht entgangen, dass sie eine spezielle Funktion ist. Andererseits: wie viel Overhead wäre es denn, eine angenehmere API zu präsentieren?
Verfasst: Freitag 9. Mai 2008, 21:14
von birkenfeld
Schreib eine, benchmarke sie und erleuchte uns

Verfasst: Dienstag 13. Mai 2008, 08:04
von jens
Wie wäre es damit:
Code: Alles auswählen
def import2(from_name, object_name=[]):
"""
from 'from_name' import 'object_name'
"""
obj = __import__(from_name, fromlist=[object_name])
if object_name==[]:
return obj
try:
return getattr(obj, object_name)
except AttributeError, e:
raise AttributeError(
"'%s' object has no attribute '%s" % (obj.__name__, object_name)
)
# from import
t = import2("time", "time")
print t()
# normaler import
s = import2("sys")
print s.version
d = import2("datetime", "datetime")
print d.now()
s = import2("os.path", "sep")
print s
try:
import2("existiertnicht")
except ImportError, e:
print "Fehler 1:", e
try:
import2("os", "gibtsnicht")
except AttributeError, e:
print "Fehler 2:", e
Ich frage mich, ob man beim zweiten Fehler auch lieber ein ImportError wirft?
Verfasst: Donnerstag 15. Mai 2008, 13:06
von jens
Ich hab da wohl was übersehen:
Changed in version 2.5: The level parameter was added. Changed in version 2.5: Keyword support for parameters was added.
Es sollte natürlich auch mit Python 2.4 gehen... Muß ich mal ändern...
Verfasst: Sonntag 18. Mai 2008, 20:06
von jens
Habs normal überarbeitet. Nun sollte es auch mit Python 2.4 gehen und man kann locals, globals angeben, wobei ich das bisher nie gebraucht hab.
Das ganze nun mit doctest:
Code: Alles auswählen
def import2(from_name, fromlist=None, globals={}, locals={}):
"""
A easy __import__ function.
TODO: Python 2.5 level argument not supported, yet.
Link: http://www.python-forum.de/topic-14591.html (de)
>>> import sys
>>> sys2 = import2("sys")
>>> sys is sys2
True
>>> from time import time
>>> time2 = import2("time", "time")
>>> time is time2
True
>>> from os.path import sep
>>> sep2 = import2("os.path", "sep")
>>> sep is sep2
True
>>> from os import sep, pathsep
>>> sep2, pathsep2 = import2("os", ["sep", "pathsep"])
>>> sep is sep2 ; pathsep is pathsep2
True
True
>>> import2("existiertnicht")
Traceback (most recent call last):
...
ImportError: No module named existiertnicht
>>> import2("os", "gibtsnicht")
Traceback (most recent call last):
...
AttributeError: 'os' object has no attribute 'gibtsnicht
"""
if isinstance(fromlist, basestring):
# Only one from objects name
fromlist = [fromlist]
obj = __import__(from_name, globals, locals, fromlist)
if fromlist==None:
# Without a fromlist
return obj
# get all 'fromlist' objects
result = []
for object_name in fromlist:
try:
result.append(getattr(obj, object_name))
except AttributeError, e:
msg = "'%s' object has no attribute '%s" % (
obj.__name__, object_name
)
raise AttributeError(msg)
if len(result) == 1:
return result[0]
else:
return result
if __name__ == "__main__": # doctest
#~ verbose = False
verbose = True
import doctest
doctest.testmod(verbose=verbose)
Dumm ist irgendwie, das global und local überschrieben werden. Aber wie anders benennen? Wie macht das eigentlich __import__ selbst?
EDIT: Default bei fromlist auf None gesetzt, siehe:
http://www.python-forum.de/post-105719.html#105719
Das ganze verwende ich in PyLucid hier:
http://trac.pylucid.net/browser/trunk/p ... v=1704#L29
Verfasst: Mittwoch 23. Juli 2008, 19:11
von jens
Gibts nun auch im Wiki:
[wiki]Import per String[/wiki]