Importations relatives - ModuleNotFoundError: Aucun module nommé x

179

C'est la première fois que je m'assois vraiment et que j'essaye python 3 et que je semble échouer lamentablement. J'ai les deux fichiers suivants:

  1. test.py
  2. config.py

config.py contient quelques fonctions définies ainsi que quelques variables. Je l'ai réduit à ce qui suit:

config.py

debug = True

test.py

import config
print (config.debug)

J'ai aussi un __init__.py

Cependant, j'obtiens l'erreur suivante:

ModuleNotFoundError: No module named 'config'

Je suis conscient que la convention py3 consiste à utiliser des importations absolues:

from . import config

Cependant, cela conduit à l'erreur suivante:

ImportError: cannot import name 'config'

Je ne sais donc pas quoi faire ici ... Toute aide est grandement appréciée. :)

Blitzmann
la source
Je ne peux pas reproduire l'erreur, comment exécutez-vous ce code?
Copperfield
2
Je l'exécute avec idle qui vient avec python, et aussi comme python test.py, et cela fonctionne parfaitement bien. Je n'ai pas pyCharm, mais c'est peut-être une mauvaise configuration de pyCharm qui cause le problème
Copperfield
1
Très étrange. J'utilise WinPython - téléchargez simplement vanilla Python 3.6 à partir de python.org, et cela fonctionne très bien. Jamais pensé à vérifier l'interprète! Merci!
blitzmann
1
Je suppose que quelque chose de génial se passe avec PYTHONPATH. Vérifiez vos paramètres IDE et / ou vos variables d'environnement système.
Martin Tournoij
1
J'ai exactement le même problème. Ce n'est pas pycharm! C'est python3. Cela fonctionne en python2, mais lorsque vous utilisez python3, vous voyez cette erreur! Très frustrant.

Réponses:

164

TL; DR: vous ne pouvez pas effectuer d'importations relatives à partir du fichier que vous exécutez car le __main__module ne fait pas partie d'un package.

Importations absolues - importez quelque chose de disponible sursys.path

Importations relatives - importer quelque chose par rapport au module actuel, doit faire partie d'un package

Si vous exécutez les deux variantes exactement de la même manière, l'une d'elles devrait fonctionner. Quoi qu'il en soit, voici un exemple qui devrait vous aider à comprendre ce qui se passe, ajoutons un autre main.pyfichier avec la structure générale des répertoires comme ceci:

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py

Et mettons à jour test.py pour voir ce qui se passe:

# config.py
debug = True


# test.py
print(__name__)

try:
    # Trying to find module in the parent package
    from . import config
    print(config.debug)
    del config
except ImportError:
    print('Relative import failed')

try:
    # Trying to find module on sys.path
    import config
    print(config.debug)
except ModuleNotFoundError:
    print('Absolute import failed')
# main.py
import ryan.test

Lançons d'abord test.py:

$ python ryan/test.py
__main__
Relative import failed
True

Ici, "test" est le __main__module et ne sait rien de l'appartenance à un paquet. Cependant, cela import configdevrait fonctionner, car le ryandossier sera ajouté à sys.path.

Lançons à la place main.py:

$ python main.py
ryan.test
True
Absolute import failed

Et ici, le test est à l'intérieur du paquet "ryan" et peut effectuer des importations relatives. import configéchoue car les importations relatives implicites ne sont pas autorisées dans Python 3.

J'espère que cela a aidé.

PS: si vous vous en tenez à Python 3, il n'y a plus besoin de __init__.pyfichiers.

Igonato
la source
3
Puis-je faire quelque chose pour que les importations absolues fonctionnent toujours? Comme, appeler à l' sys.path.append('/some/path/my_module')intérieur de /some/path/my_module/__init__.py?
James T.
4
@JamesT. Oui, il est assez courant de modifier sys.pathpendant l'exécution ( github.com / ... ). Vous pouvez également définir la variable d'environnement PYTHONPATH.
Igonato
6
"si vous vous en tenez à Python 3, il n'y a plus besoin de __init__.pyfichiers." Intéressant. Pouvez-vous élaborer sur ce sujet? J'avais l'impression que le mécanisme de résolution des paquets n'a pas beaucoup changé entre 2 et 3.
Kevin
2
"si vous vous en tenez à Python 3, il n'y a plus besoin de __init__.pyfichiers." Inversement, pouvez-vous décrire les choses si nous voulons qu'un package fonctionne à la fois en 2 et en 3? Et voir la tristement désuète 2009 À quoi ça sert __init__.py? et sa réponse la plus votée "Cela fait partie d'un package" . Nous devons commencer à insister sur la distinction «paquet régulier [ancien, pré-3.3]» et «paquet d'espace de noms [3.3+]» partout et souvent.
smci
61

Je l'ai compris. Très frustrant, surtout venant de python2.

Vous devez ajouter un .au module, qu'il soit relatif ou absolu ou non.

J'ai créé la configuration du répertoire comme suit.

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py

modx.py

def does_something():
    return "I gave you this string."

mody.py

from modx import does_something

def loaded():
    string = does_something()
    print(string)

main.py

from lib import mody

mody.loaded()

quand j'exécute main, c'est ce qui se passe

$ python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from lib import mody
  File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
    from modx import does_something
ImportError: No module named 'modx'

J'ai couru 2to3, et la sortie principale était la suivante

RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
@@ -1,4 +1,4 @@
-from modx import does_something
+from .modx import does_something

 def loaded():
     string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py

J'ai dû modifier la déclaration d'importation de mody.py pour le corriger

try:
    from modx import does_something
except ImportError:
    from .modx import does_something


def loaded():
    string = does_something()
    print(string)

Ensuite, j'ai exécuté à nouveau main.py et j'ai obtenu la sortie attendue

$ python main.py
I gave you this string.

Enfin, juste pour le nettoyer et le rendre portable entre 2 et 3.

from __future__ import absolute_import
from .modx import does_something

la source
1
Il convient de noter que la try/exceptprocédure de chargement est le véritable ingrédient qui fonctionne ici (comme certaines personnes devront utiliser try:scripts.modxet except: modx), et c'est ce qui a résolu ce problème pour moi.
Justapigeon
40

La configuration de PYTHONPATH peut également aider à résoudre ce problème.

Voici comment cela peut être fait sous Windows

set PYTHONPATH=.

Santosh Pillai
la source
11
définir PYTHONPATH dans le répertoire de code principal a résolu le problème pour moi!
Geek
1
Fonctionne également sous Linux. export PYTHONPATH =.
rjdkolb
29

Vous devez ajouter le chemin du module à PYTHONPATH.


Pour UNIX (Linux, OSX, ...)

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

Pour les fenêtres

set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\module\
Giorgos Myrianthous
la source
4
Un grand merci @Giorgos! Cela est particulièrement vrai lorsque vous essayez de définir un répertoire racine dans une image docker.
Tony Fraser
15

J'ai essayé votre exemple

from . import config

obtenu l'erreur SystemError suivante:
/usr/bin/python3.4 test.py
Traceback (dernier appel le plus récent):
Fichier "test.py", ligne 1, à
partir de. import config
SystemError: module parent «» non chargé, impossible d'effectuer une importation relative


Cela fonctionnera pour moi:

import config
print('debug=%s'%config.debug)

>>>debug=True

Testé avec Python: 3.4.2 - PyCharm 2016.3.2


A côté de cela PyCharm vous propose d' importer ce nom .
Vous devez cliquer configet une icône d'aide apparaît. entrez la description de l'image ici

cuisinière
la source
11

Vous pouvez simplement ajouter le fichier suivant à votre répertoire de tests, puis python l'exécutera avant les tests

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
Vinod Rane
la source
C'est exactement ce que je recherchais. Merci d'avoir partagé cette réponse !!!
Mayur
Faire quelque chose comme ça donne une erreur linter (pylint3). L'erreur est similaire à celle-ci. filename.py:12:0: C0413: Importer "import abc.def.ghi.file_util as file_util" doit être placé en haut du module (mauvaise-import-position)
Sharad
6

Définissez PYTHONPATHla variable d'environnement dans le répertoire racine du projet.

Considérant UNIX-like:

export PYTHONPATH=.
Manasouza
la source
4

Cet exemple fonctionne sur Python 3.6.

Je suggère d'aller Run -> Edit Configurationsdans PyCharm, de supprimer toutes les entrées et d'essayer à nouveau d'exécuter le code via PyCharm.

Si cela ne fonctionne pas, vérifiez votre interpréteur de projet (Paramètres -> Interpréteur de projet) et exécutez les paramètres de configuration par défaut (Exécuter -> Modifier les configurations ...).

Grue Carson
la source
4

Déclarez la liste sys.path correcte avant d'appeler le module:

import os, sys

#'/home/user/example/parent/child'
current_path = os.path.abspath('.')

#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)

sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')
HoangYell
la source
1

Comme indiqué dans les commentaires de l'article original, cela semblait être un problème avec l'interpréteur python que j'utilisais pour une raison quelconque, et pas quelque chose de mal avec les scripts python. Je suis passé du bundle WinPython au python 3.6 officiel de python.org et cela a très bien fonctionné. Merci à tous pour l'aide :)

Blitzmann
la source
1
Hmm déteste dire ça mais la même chose vient de m'arriver. La recréation de l'environnement résout le problème. Dans mon cas, j'obtenais cette erreur lors de l'exécution des tests. Dans le même environnement, essayez d'importer le même module travaillé. La recréation de l'environnement les a toutes corrigées (même version python 3.6)
naoko
1
Différents IDE ont une manière différente de gérer les chemins spécialement pour les fichiers source du projet (vues, modules, modèles, etc.) Si votre projet est structuré et codé correctement, alors il devrait fonctionner avec tous les IDE (standard). Avoir des problèmes avec les IDE populaires tels que WinPython signifie que le problème vient effectivement de votre projet. Comme mentionné ci-dessus, le problème est "Vous devez ajouter un. Au module" par user3159377 qui devrait être la réponse acceptée.
winux
1

Si vous utilisez python 3+, essayez d'ajouter les lignes ci-dessous

import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)
Vivek Garg
la source
0

Essayer

from . import config

Cela permet d'importer à partir du même niveau de dossier. Si vous essayez directement d'importer, cela suppose qu'il s'agit d'un subordonné

Arny Boy
la source