Comment corriger "tentative d'importation relative en non-paquet" même avec init.py

j'essaie de suivre PEP 328 , avec la structure de répertoire suivante:

pkg/
  __init__.py
  components/
    core.py
    __init__.py
  tests/
    core_test.py
    __init__.py

dans core_test.py j'ai la déclaration d'importation suivante

from ..components.core import GameLoopEvents

cependant, quand je cours, j'obtiens l'erreur suivante:

tests$ python core_test.py 
Traceback (most recent call last):
  File "core_test.py", line 3, in <module>
    from ..components.core import GameLoopEvents
ValueError: Attempted relative import in non-package

J'ai trouvé " le chemin relatif ne fonctionne pas même avec __init__.py " et " " Importer un module à partir d'un chemin relatif " mais ils n'ont pas d'aide.

y a-t-il quelque chose que je manque ici?

614
demandé sur Community 2012-07-18 11:59:14

12 réponses

Oui. Vous n'êtes pas à l'utiliser comme un paquet.

python -m pkg.tests.core_test
376
répondu Ignacio Vazquez-Abrams 2012-07-18 08:01:04

pour développer sur Ignacio Vazquez-Abrams réponse:

le mécanisme D'importation Python fonctionne relativement au __name__ du fichier courant. Lorsque vous exécutez un fichier directement, il n'a pas son nom habituel, mais a "__main__" comme son nom au lieu. Donc les importations relatives ne marchent pas.

vous pouvez, comme Igancio l'a suggéré, l'exécuter en utilisant l'option -m . Si vous avez une partie de votre paquet qui est destiné à être lancé comme un script, vous pouvez également utiliser l'attribut __package__ pour indiquer à ce fichier quel nom il est censé avoir dans la hiérarchie du paquet.

Voir http://www.python.org/dev/peps/pep-0366/ pour plus de détails.

547
répondu BrenBarn 2018-04-25 11:02:57

Vous pouvez utiliser import components.core directement, si vous ajoutez le répertoire courant sys.path :

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
192
répondu ihm 2016-02-22 19:44:29

Cela dépend de comment vous voulez lancer votre script.

Si vous voulez lancer votre UnitTest à partir de la ligne de commande classique", c'est:

python tests/core_test.py

puis, puisque dans ce cas 'composants' et 'tests' sont des dossiers frères et sœurs, vous pouvez importer le module relatif soit en utilisant le insérer ou le ajouter méthode du sys.chemin module. Quelque chose comme:

import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents

sinon, vous pouvez lancer votre script avec l'argument "- m" (notez que dans ce cas, nous parlons d'un paquet, et donc vous ne devez pas donner le ".PY ' extension), c'est-à-dire:

python -m pkg.tests.core_test

dans un tel cas, vous pouvez simplement utiliser l'importation relative comme vous avez été à faire:

from ..components.core import GameLoopEvents

vous pouvez enfin mélanger les deux approches, de sorte que votre script fonctionnera peu importe comment il est appelé. Par exemple:

if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
        from components.core import GameLoopEvents
    else:
        from ..components.core import GameLoopEvents
161
répondu Paolo Rovelli 2015-01-10 16:55:01

In core_test.py, faire ce qui suit:

import sys
sys.path.append('../components')
from core import GameLoopEvents
13
répondu Allan Mwesigwa 2017-01-10 17:44:57

si votre étui d'utilisation est pour exécuter des tests, et il Coume qu'il est, alors vous pouvez faire ce qui suit. Au lieu d'exécuter votre script de test comme python core_test.py utilisez un framework de test tel que pytest . Sur la ligne de commande, vous pouvez entrer

$$ py.test

qui exécutera les tests dans votre répertoire. Cela contourne la question de __name__ étant __main__ qui a été souligné par @BrenBarn. Ensuite, mettez un fichier __init__.py vide dans votre répertoire de test. , cela fera du répertoire test une partie de votre paquet. Alors vous pourrez faire

from ..components.core import GameLoopEvents

cependant, si vous exécutez votre script de test en tant que programme principal, les choses vont encore échouer. Alors utilisez juste le coureur de test. Peut-être que cela fonctionne aussi avec d'autres coureurs comme nosetests mais je n'ai pas vérifié. Espérons que cette aide.

9
répondu deepak 2015-11-13 17:00:09

mon quick-fix est d'ajouter le répertoire au chemin:

import sys
sys.path.insert(0, '../components/')
4
répondu v4gil 2016-11-01 07:19:41

vieux fil. J'ai découvert que l'ajout d'un __all__= ['submodule', ...] à la __ _ init__.py fichier puis en utilisant le from <CURRENT_MODULE> import * dans la cible fonctionne très bien.

2
répondu Laurent 2018-04-18 17:13:32

si quelqu'un cherche une solution, j'en tombe sur une. Voici un peu de contexte. J'ai voulu tester une des méthodes que j'ai dans un fichier. Quand je l'exécute de l'intérieur

if __name__ == "__main__":

elle s'est toujours plainte des importations relatives. J'ai essayé d'appliquer les solutions ci-dessus, mais n'a pas réussi à travailler, car il y avait beaucoup de fichiers imbriqués, chacun avec des importations multiples.

voilà ce que j'ai fait. Je viens de créer un lanceur, un programme externe qui importez méthodes nécessaires et de les appeler. Bien que ce ne soit pas une bonne solution, ça marche.

0
répondu HappyWaters 2018-02-21 10:17:58

Essayez cette

import components
from components import *
0
répondu Vaishnavi Bala 2018-05-24 05:41:17

vous pouvez utiliser from pkg.components.core import GameLoopEvents , par exemple j'utilise pycharm, ci-dessous est mon image de structure de projet, je viens d'importer à partir du paquet racine, puis il fonctionne:

enter image description here

0
répondu Jayhello 2018-07-14 11:20:11

Comme Paolo , a déclaré, nous avons 2 méthodes d'appel:

1) python -m tests.core_test
2) python tests/core_test.py

Une différence entre eux est sys.chaîne de chemin[0]. Depuis , l'interpréteur recherchera sys.chemin lors de l'importation de , nous pouvons faire avec tests/core_test.py :

if __name__ == '__main__':
    import sys
    from pathlib import Path
    sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
    from components import core
    <other stuff>

et plus après cela, nous pouvons courir core_test.py avec d'autres méthodes:

cd tests
python core_test.py
python -m core_test
...

Note, py36 testé seulement.

0
répondu zhengcao 2018-09-20 08:01:03