importieren von Modulen aus Package

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Donnerstag 8. Mai 2008, 15:57

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?
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Donnerstag 8. Mai 2008, 18:03

__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.
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Donnerstag 8. Mai 2008, 18:13

Danke :oops:
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Donnerstag 8. Mai 2008, 18:38

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>
TUFKAB – the user formerly known as blackbird
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 9. Mai 2008, 00:17

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.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 9. Mai 2008, 08:20

Jep, Die API von __import__ ist grauenhaft :(

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Freitag 9. Mai 2008, 20:22

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.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 9. Mai 2008, 21:11

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?
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Freitag 9. Mai 2008, 21:14

Schreib eine, benchmarke sie und erleuchte uns :D
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 13. Mai 2008, 08:04

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?

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Donnerstag 15. Mai 2008, 13:06

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...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sonntag 18. Mai 2008, 20:06

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

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 23. Juli 2008, 19:11

Gibts nun auch im Wiki:
[wiki]Import per String[/wiki]

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten