80 votes

ModuleNotFoundError : Aucun module nommé '__main__.xxxx' ; '__main__' n'est pas un paquetage.

J'essaie actuellement de travailler en Python3 et d'utiliser les importations absolues pour importer un module dans un autre, mais je reçois l'erreur suivante ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package . Considérez cette structure de projet :

proj
    __init__.py3 (empty)
    moduleA.py3
    moduleB.py3

moduleA.py3

from .moduleB import ModuleB
ModuleB.hello()

moduleB.py3

class ModuleB:
    def hello():
        print("hello world")

Puis en courant python3 moduleA.py3 donne l'erreur. Que faut-il modifier ici ?

2 votes

Le signe '.' ne fonctionne comme vous le souhaitez que lorsque le fichier dans lequel il se trouve est dans un paquet.

2 votes

@anonymoose, "proj" n'est pas un paquet ? puisqu'il possède un init .py3 ?

3 votes

Il n'est pas possible d'utiliser le "." en tête des importations et de faire en sorte que cela fonctionne comme vous le souhaitez lorsque vous exécutez le fichier directement avec Python. Vous devez importer le fichier. Si vous avez placé un autre fichier en dehors de proj qui avait import moduleA je pense que vous obtiendrez le résultat que vous attendez.

53voto

Md. Sabuj Sarker Points 441

.moduleB est une importation relative. L'importation relative ne fonctionne que lorsque le module parent est importé ou chargé en premier. Cela signifie que vous devez avoir proj importé quelque part dans votre environnement d'exécution actuel. Lorsque vous utilisez la commande python3 moduleA.py3 il n'a aucune chance d'importer le module parent. Vous pouvez :

  • from proj.moduleB import moduleB OU
  • Vous pouvez créer un autre script, par exemple run.py pour invoquer from proj import moduleA

Bonne chance dans votre voyage vers le merveilleux pays des pythons.

2 votes

Et ce sont des importations hilarantes et ratées.

42voto

itachi Points 986

Avant-propos

Je suis en train de développer un projet qui est en fait un paquetage Python qui peut être installé par l'intermédiaire de pip mais il expose également une interface en ligne de commande. Je n'ai pas de problèmes pour exécuter mon projet après l'avoir installé avec pip install . mais bon, qui fait ça à chaque fois qu'il change quelque chose dans un des fichiers du projet ? J'avais besoin de faire passer le tout par un simple python mypackage/main.py .

/my-project
    - README.md
    - setup.py
    /mypackage
      - __init__.py
      - main.py
      - common.py

Les différents visages d'un même problème

J'ai essayé d'importer quelques fonctions dans main.py de mon common.py module. J'ai essayé différentes configurations qui ont donné différentes erreurs, et je veux partager avec vous mes observations et laisser une note rapide pour les futurs moi aussi.

Importation relative

La première chose que j'ai essayée était une importation relative :

from .common import my_func

J'ai exécuté mon application avec simple : python mypackage/main.py . Malheureusement, cela a donné l'erreur suivante :

ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package

La cause de ce problème est que le main.py a été exécuté directement par python devenant ainsi le module principal nommé __main__ . Si nous relions cette information à l'importation relative que nous avons utilisée, nous obtenons ce que nous avons dans le message d'erreur : __main__.common . Ceci est expliqué dans le Documentation Python :

Notez que les importations relatives sont basées sur le nom du module courant. Puisque le nom du module principal est toujours __main__ Les modules destinés à être utilisés comme module principal d'une application Python doivent toujours utiliser des importations absolues.

Lorsque j'ai installé mon paquet avec pip install . puis l'a exécuté, il a parfaitement fonctionné. J'ai également pu importer mypackage.main dans une console Python. Il semble donc qu'il n'y ait un problème qu'en l'exécutant directement.

Importation absolue

Suivons les conseils de la documentation et changeons l'instruction d'importation en quelque chose de différent :

from common import my_func

Si nous essayons maintenant de l'exécuter comme avant : python mypackage/main.py alors cela fonctionne comme prévu ! Mais il y a un problème lorsque, comme moi, vous développez quelque chose qui doit fonctionner en tant qu'outil autonome en ligne de commande après l'avoir installé avec la commande pip . J'ai installé mon paquet avec pip install . et ensuite j'ai essayé de l'exécuter...

ModuleNotFoundError: No module named 'common'

Pire encore, lorsque j'ai ouvert une console Python, et que j'ai essayé d'importer le fichier main manuellement ( import mypackage.main ), puis j'ai obtenu la même erreur que ci-dessus. La raison en est simple : common n'est plus un import relatif, donc Python essaie de le trouver dans les paquets installés. Nous n'avons pas de tel paquet, c'est pourquoi il échoue.

La solution de l'importation absolue ne fonctionne bien que si vous créez une application Python typique qui est exécutée avec un fichier de type python commandement.

Importation avec un nom de paquet

Il existe également une troisième possibilité d'importer le common module :

from mypackage.common import my_func

Ce n'est pas très différent de la Importation relative l'approche, tant que nous le faisons à partir du contexte de mypackage . Et encore une fois, j'essaie de l'exécuter avec python mypackage/main.py finit par être similaire :

ModuleNotFoundError: No module named 'mypackage'

Comme cela peut être irritant, l'interprète a raison, vous n'avez pas installé ce paquet.

La solution

Pour les applications Python simples

Utilisez simplement les importations absolues (sans le point), et tout ira bien.

Pour les applications Python installables en cours de développement

Utilisez des importations relatives, ou des importations avec un nom de paquet au début, car vous en avez besoin comme ça lorsque votre application est installée. Lorsqu'il s'agit d'exécuter un tel module en développement, Python peut être exécuté avec la commande -m option :

-m mod : run library module as a script (terminates option list)

Ainsi, au lieu de python mypackage/main.py fais-le comme ça : python -m mypackage.main .

26voto

Dennis Points 600

En plus de la réponse de md-sabuj-sarker, il y a un très bon exemple dans le document Documentation des modules Python .

Voici ce que dit la documentation sur Références intra-package :

Notez que les importations relatives sont basées sur le nom du module courant. Puisque le nom du module principal est toujours "__main__" Les modules destinés à être utilisés comme module principal d'une application Python doivent toujours utiliser des importations absolues.

Si vous exécutez python3 moduleA.py3 , moduleA est utilisé comme module principal, donc l'utilisation de l'import absolu semble être la bonne chose à faire.

Attention toutefois, cette importation absolue ( from package.module import something ) échoue si, pour une raison quelconque, le paquet contient un fichier module avec le même nom que le paquet (du moins, sur mon Python 3.7). Donc, par exemple, cela échouerait si vous avez (en utilisant l'exemple de l'OP) :

proj/
    __init__.py (empty)
    proj.py (same name as package)
    moduleA.py
    moduleB.py

dans ce cas, vous obtiendrez :

ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package

Vous pouvez également supprimer le . sur from .moduleB import comme suggéré ici et ici qui semble fonctionner, bien que mon PyCharm (2018.2.4) marque cela comme une "référence non résolue" et ne parvient pas à l'autocomplétion.

3 votes

Fonctionne pour moi. pycharm a allumé la ligne d'importation, mais il fonctionne sans problème ! (Honte à toi, pycharm)

2 votes

@KaiWang Pour éviter que PyCharm marque ceci comme une "référence non résolue", vous pouvez marquer le répertoire Root comme source Root .

3voto

Toby Points 1

Vous pouvez peut-être faire ceci avant d'importer le module

moduleA.py3

import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from moduleB import ModuleB
ModuleB.hello()

Ajouter le répertoire courant au répertoire d'environnement

0voto

Edgar Mejía Points 29

Il suffit de renommer le fichier de l'endroit où vous exécutez l'application en main.py :

from app import app

if __name__ == '__main__':
    app.run()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X