web-dev-qa-db-fra.com

Module introuvable lors de l'importation dans Jupyter Notebook

J'ai le paquet suivant (et le répertoire de travail):

WorkingDirectory--
                 |--MyPackage--
                 |            |--__init__.py
                 |            |--module1.py
                 |            |--module2.py
                 |
                 |--notebook.ipynb

Dans __init__.py j'ai:

import module1
import module2

Si j'essaie d'importer MyPackage dans mon cahier:

import MyPackage as mp 

Je vais obtenir ModuleNotFoundError: No module named 'module1'. Mais l'importation fonctionne correctement si j'exécute le script en dehors d'un bloc-notes: si je crée test.py dans le même répertoire et que je fais de même que dans le bloc-notes, l'importation fonctionnerait correctement. Cela fonctionnera à l'intérieur du cahier si j'utilise un nom complet en __init__.py (import MyPackage.module1).

Quelle est la raison du comportement différent d'importation?

J'ai confirmé que le répertoire de travail du cahier est WorkingDirectory.

---Mettre à jour---------

L'erreur exacte est:

C:\Users\Me\Documents\Working Directory\MyPackage\__init__.py in <module>()
---> 17 import module1

ModuleNotFoundError: No module named 'module1'

Mon problème diffère de la duplication possible:

  1. L'ordinateur portable a été en mesure de trouver le package, mais uniquement en mesure de charger le module. Cela a été déduit de la substitution de module1 par MyPackage.module1 a bien fonctionné et suggère que ce n'est peut-être pas un problème lié à PATH.

  2. Je ai cded dans WorkingDirectory et démarré le serveur là-bas. Le répertoire de travail devrait être le dossier contenant mon paquet.

7
Ryan

Je suis à peu près sûr que ce problème est lié et que la réponse proposée vous aidera: https://stackoverflow.com/a/15622021/7458681

tl; dr le cwd du serveur portable est toujours le chemin de base où vous avez démarré le serveur, peu importe que vous exécutiez import os os.getcwd() dit. Utilisez import sys sys.path.append("/path/to/your/module/folder")

Je l'ai exécuté avec quelques modules factices dans la même structure que celle que vous aviez spécifiée. Avant de modifier sys.path, il ne fonctionnerait pas et après cela,

5
Louise Davies

La raison en est que votre MyPackage/__init__.py est exécuté à partir du répertoire de travail actuel. Par exemple. de WorkingDirectory dans ce cas. Cela signifie que cet interpréteur ne peut pas trouver le module nommé module1 puisqu'il ne se trouve ni dans le répertoire des packages actuels ni dans celui des packages globaux.

Il existe peu de solutions de contournement pour cela. Par exemple, vous pouvez remplacer temporairement un répertoire de travail en cours comme ceci

cwd = os.getcwd()
csd = __path__[0]
os.chdir(csd)

et ensuite, une fois toutes les actions d'initialisation de package telles que import module1 terminées, restaurez le répertoire de travail de "l'appelant" avec os.chdir(cwd).

C'est une très mauvaise approche pour moi, car, par exemple, si une exception est générée lors des actions d'initialisation, un répertoire de travail ne serait pas restauré. Vous aurez besoin de jouer avec les instructions try..except pour résoudre ce problème. 

Une autre approche consisterait à utiliser les importations relatives. Reportez-vous à la documentation pour plus de détails.

Voici un exemple de MyPackage/__init__.py qui fonctionnera pour votre exemple:

from .module1 import *

Mais il présente peu d'inconvénients que l'on trouve plutôt empiriquement que par le biais de la documentation. Par exemple, vous ne pouvez pas écrire quelque chose comme import .module1.


Upd: J'ai constaté que cette exception était déclenchée même si import MyPackage est exécuté à partir de la console Python habituelle. Pas de IPython ou Jupyter Notebook. Donc, cela ne semble pas être un problème IPython lui-même.

0