Importations de paquets frères


225

J'ai essayé de lire des questions sur les importations de frères et même la documentation du paquet , mais je n'ai pas encore trouvé de réponse.

Avec la structure suivante:

├── LICENSE.md
├── README.md
├── api
│   ├── __init__.py
│   ├── api.py
│   └── api_key.py
├── examples
│   ├── __init__.py
│   ├── example_one.py
│   └── example_two.py
└── tests
│   ├── __init__.py
│   └── test_one.py

Comment les scripts dans les exampleset testsrépertoires importer à partir du apimodule et être exécuté à partir du commandline?

De plus, j'aimerais éviter le sys.path.inserttruc horrible pour chaque fichier. Cela peut sûrement être fait en Python, non?


7
Je recommande de sauter tous les sys.pathhacks et de lire la seule solution réelle qui a été publiée jusqu'à présent (après 7 ans!).
Aran-Fey

1
Au fait, il y a encore de la place pour une autre bonne solution: séparer le code exécutable du code de la bibliothèque; la plupart du temps, un script à l'intérieur d'un package ne devrait pas être exécutable pour commencer.
Aran-Fey

C'est tellement utile, à la fois la question et les réponses. Je suis juste curieux, comment se fait-il que "Réponse acceptée" ne soit pas la même que celle qui a reçu la prime dans ce cas?
Indominus

@ Aran-Fey C'est un rappel sous-estimé dans ces questions et réponses relatives aux erreurs d'importation. Je cherchais un hack depuis tout ce temps, mais au fond de moi, je savais qu'il y avait un moyen simple de me sortir du problème. Cela ne veut pas dire que c'est la solution pour tout le monde ici qui lit, mais c'est un bon rappel comme cela pourrait l'être pour beaucoup.
colorlace le

Réponses:


83

Sept ans après

Depuis que j'ai écrit la réponse ci-dessous, la modification sys.pathest toujours une astuce rapide qui fonctionne bien pour les scripts privés, mais il y a eu plusieurs améliorations

  • L'installation du package (dans un virtualenv ou non) vous donnera ce que vous voulez, bien que je suggère d'utiliser pip pour le faire plutôt que d'utiliser directement setuptools (et d'utiliser setup.cfgpour stocker les métadonnées)
  • L'utilisation de l' -mindicateur et l'exécution en tant que package fonctionnent également (mais s'avéreront un peu gênantes si vous souhaitez convertir votre répertoire de travail en un package installable).
  • Pour les tests, en particulier, pytest est capable de trouver le package api dans cette situation et s'occupe des sys.pathhacks pour vous

Cela dépend donc vraiment de ce que vous voulez faire. Dans votre cas, cependant, comme il semble que votre objectif soit de créer un package approprié à un moment donné, l'installation via pip -eest probablement votre meilleur pari, même si elle n'est pas encore parfaite.

Ancienne réponse

Comme déjà indiqué ailleurs, la terrible vérité est que vous devez faire de vilains hacks pour autoriser les importations à partir de modules frères ou de packages parents à partir d'un __main__module. La question est détaillée dans la PEP 366 . La PEP 3122 a tenté de traiter les importations d'une manière plus rationnelle, mais Guido l'a rejetée à cause de

Le seul cas d'utilisation semble être l'exécution de scripts qui se trouvent dans le répertoire d'un module, que j'ai toujours vu comme un anti-modèle.

( ici )

Cependant, j'utilise ce modèle régulièrement avec

# Ugly hack to allow absolute import from the root folder
# whatever its name is. Please forgive the heresy.
if __name__ == "__main__" and __package__ is None:
    from sys import path
    from os.path import dirname as dir

    path.append(dir(path[0]))
    __package__ = "examples"

import api

Voici path[0]le dossier parent de votre script en cours d'exécution et dir(path[0])votre dossier de niveau supérieur.

Je n'ai toujours pas pu utiliser les importations relatives avec cela, mais cela permet des importations absolues depuis le niveau supérieur (dans le apidossier parent de votre exemple ).


3
vous n'avez pas à le faire si vous exécutez à partir d'un répertoire de projet en utilisant -mform ou si vous installez le package (pip et virtualenv facilitent les choses)
jfs

2
Comment pytest trouve-t-il le package API pour vous? De manière amusante, j'ai trouvé ce fil parce que je rencontre ce problème spécifiquement avec l'importation de paquets pytest et frères.
JuniorIncanter

1
J'ai deux questions, s'il vous plaît. 1. Votre modèle semble fonctionner sans __package__ = "examples"pour moi. Pourquoi l'utilisez-vous? 2. Dans quelle situation se trouve __name__ == "__main__"mais __package__n'est pas None?
actual_panda

@actual_panda Le réglage est __packages__utile si vous voulez un chemin absolu tel que examples.apitravailler iirc (mais cela fait longtemps que je n'ai pas fait cela pour la dernière fois) et vérifier que le paquet n'est pas None était principalement une solution de sécurité pour les situations étranges et la pérennité.
Evpok

Bon sang, si seulement d'autres langages rendaient le même processus aussi simple qu'en Python. Je vois pourquoi tout le monde aime cette langue. Btw, la documentation est également excellente. J'adore extraire les types de retour du texte non structuré, c'est un bon changement par rapport à Javadoc et phpdoc. ffs ....
matt

194

Fatigué des hacks sys.path?

Il existe de nombreux sys.path.append-hacks disponibles, mais j'ai trouvé un autre moyen de résoudre le problème en cours.

Sommaire

  • Enveloppez le code dans un dossier (par exemple packaged_stuff)
  • Utilisez create setup.pyscript où vous utilisez setuptools.setup () .
  • Pip installe le package à l'état modifiable avec pip install -e <myproject_folder>
  • Importer avec from packaged_stuff.modulename import function_name

Installer

Le point de départ est la structure de fichiers que vous avez fournie, enveloppée dans un dossier appelé myproject.

.
└── myproject
    ├── api
    │   ├── api_key.py
    │   ├── api.py
    │   └── __init__.py
    ├── examples
    │   ├── example_one.py
    │   ├── example_two.py
    │   └── __init__.py
    ├── LICENCE.md
    ├── README.md
    └── tests
        ├── __init__.py
        └── test_one.py

J'appellerai le .dossier racine, et dans mon exemple, il se trouve à C:\tmp\test_imports\.

api.py

Comme cas de test, utilisons ce qui suit ./api/api.py

def function_from_api():
    return 'I am the return value from api.api!'

test_one.py

from api.api import function_from_api

def test_function():
    print(function_from_api())

if __name__ == '__main__':
    test_function()

Essayez d'exécuter test_one:

PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
  File ".\myproject\tests\test_one.py", line 1, in <module>
    from api.api import function_from_api
ModuleNotFoundError: No module named 'api'

Essayer également les importations relatives ne fonctionnera pas:

L'utilisation from ..api.api import function_from_apientraînerait

PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
  File ".\tests\test_one.py", line 1, in <module>
    from ..api.api import function_from_api
ValueError: attempted relative import beyond top-level package

Pas

  1. Créez un fichier setup.py dans le répertoire racine

Le contenu du setup.pyserait *

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())
  1. Utilisez un environnement virtuel

Si vous êtes familiarisé avec les environnements virtuels, activez-en un et passez à l'étape suivante. L'utilisation d'environnements virtuels n'est pas absolument nécessaire, mais ils vous aideront vraiment à long terme (lorsque vous avez plus d'un projet en cours ..). Les étapes les plus élémentaires sont (exécutées dans le dossier racine)

  • Créer un environnement virtuel
    • python -m venv venv
  • Activer l'environnement virtuel
    • source ./venv/bin/activate(Linux, macOS) ou ./venv/Scripts/activate(Win)

Pour en savoir plus à ce sujet, il suffit de rechercher sur Google "tutoriel d'environnement virtuel python" ou similaire. Vous n'avez probablement jamais besoin d'autres commandes que la création, l'activation et la désactivation.

Une fois que vous avez créé et activé un environnement virtuel, votre console doit donner le nom de l'environnement virtuel entre parenthèses

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

et votre arborescence de dossiers devrait ressembler à ceci **

.
├── myproject
│   ├── api
│   │   ├── api_key.py
│   │   ├── api.py
│   │   └── __init__.py
│   ├── examples
│   │   ├── example_one.py
│   │   ├── example_two.py
│   │   └── __init__.py
│   ├── LICENCE.md
│   ├── README.md
│   └── tests
│       ├── __init__.py
│       └── test_one.py
├── setup.py
└── venv
    ├── Include
    ├── Lib
    ├── pyvenv.cfg
    └── Scripts [87 entries exceeds filelimit, not opening dir]
  1. pip installez votre projet dans un état modifiable

Installez votre package de niveau supérieur en myprojectutilisant pip. L'astuce consiste à utiliser le -edrapeau lors de l'installation. De cette façon, il est installé dans un état modifiable et toutes les modifications apportées aux fichiers .py seront automatiquement incluses dans le package installé.

Dans le répertoire racine, exécutez

pip install -e . (notez le point, il signifie "répertoire courant")

Vous pouvez également voir qu'il est installé en utilisant pip freeze

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
  1. Ajoutez myproject.à vos importations

Notez que vous devrez ajouter myproject.uniquement dans les importations qui ne fonctionneraient pas autrement. Les importations qui ont fonctionné sans le setup.py& pip installfonctionneront toujours correctement. Voir un exemple ci-dessous.


Testez la solution

Maintenant, testons la solution en utilisant api.pydéfinie ci-dessus et test_one.pydéfinie ci-dessous.

test_one.py

from myproject.api.api import function_from_api

def test_function():
    print(function_from_api())

if __name__ == '__main__':
    test_function()

exécuter le test

(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!

* Voir la documentation de setuptools pour des exemples plus détaillés de setup.py.

** En réalité, vous pouvez placer votre environnement virtuel n'importe où sur votre disque dur.


16
Merci pour le message détaillé. Voici mon problème. Si je fais tout ce que vous avez dit et que je fais un gel de pip, j'obtiens une ligne -e git+https://username@bitbucket.org/folder/myproject.git@f65466656XXXXX#egg=myprojectUne idée sur la façon de résoudre?
Si lun

2
Pourquoi la solution d'importation relative ne fonctionne-t-elle pas? Je vous crois, mais j'essaie de comprendre le système alambiqué de Python.
Jared Nielsen

10
Quelqu'un a-t-il des problèmes avec un ModuleNotFoundError? J'ai installé «myproject» dans un virtualenv en suivant ces étapes, et lorsque j'entre dans une session interprétée et que j'exécute, import myprojectj'obtiens ModuleNotFoundError: No module named 'myproject'? pip list installed | grep myprojectmontre qu'il est là, que le répertoire est correct et que la version de pipet pythonest vérifiée comme étant correcte.
TheseKind

3
J'ai passé environ 2 heures à essayer de comprendre comment faire fonctionner les importations relatives, et cette réponse a finalement fait quelque chose de sensé. 👍👍
Graham Lea

5
Ce que je trouve écœurant, c'est que je dois venir à stackoverflow pour trouver une vraie réponse sur la façon de faire correctement les importations relatives. La documentation autour de ce truc a vraiment besoin d'être améliorée.
teuber789 le

45

Voici une autre alternative que j'insère en haut des fichiers Python dans le testsdossier:

# Path hack.
import sys, os
sys.path.insert(0, os.path.abspath('..'))

1
+1 vraiment simple et cela a parfaitement fonctionné. Vous devez ajouter la classe parente à l'importation (ex api.api, examples.example_two) mais je préfère cela.
Evan Plaice

10
Je pense qu'il vaut la peine de mentionner aux débutants (comme moi) ..qu'ici est relatif au répertoire à partir duquel vous exécutez --- pas le répertoire contenant ce fichier test / exemple. J'exécute à partir du répertoire du projet, et j'avais besoin à la ./place. J'espère que ceci aide quelqu'un d'autre.
Joshua Detwiler

@JoshDetwiler, oui absolument. Je n'étais pas au courant de ça. Merci.
doak

1
C'est une mauvaise réponse. Pirater le chemin n'est pas une bonne pratique; c'est scandaleux de voir combien il est utilisé dans le monde python. L'un des principaux points de cette question était de voir comment les importations pouvaient se faire tout en évitant ce genre de piratage.
teuber789 le

1
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))@JoshuaDetwiler
vldbnc

33

Vous n'avez pas besoin et ne devriez pas pirater sys.pathsauf si c'est nécessaire et dans ce cas, ce n'est pas le cas. Utilisation:

import api.api_key # in tests, examples

Exécuter à partir du répertoire du projet: python -m tests.test_one.

Vous devriez probablement vous déplacer tests(si ce sont les tests unitaires de l'API) à l'intérieur apiet exécuter python -m api.testpour exécuter tous les tests (en supposant qu'il y en ait un __main__.py) ou python -m api.test.test_onepour exécuter à la test_oneplace.

Vous pouvez également supprimer __init__.pyde examples(ce n'est pas un package Python) et exécuter les exemples dans un virtualenv où apiest installé par exemple, pip install -e .dans un virtualenv installerait le apipackage inplace si vous avez le bon setup.py.


@Alex la réponse ne suppose pas que les tests sont des tests API, sauf pour le paragraphe où il est dit explicitement "si ce sont les tests unitaires de l'API " .
jfs

malheureusement, vous êtes coincé avec l'exécution à partir du répertoire racine et PyCharm ne trouve toujours pas le fichier pour ses fonctions intéressantes
mhstnsc

@mhstnsc: ce n'est pas correct. Vous devriez pouvoir exécuter python -m api.test.test_onede n'importe où lorsque le virtualenv est activé. Si vous ne pouvez pas configurer PyCharm pour exécuter vos tests, essayez de poser une nouvelle question de débordement de pile (si vous ne trouvez pas de question existante sur ce sujet).
jfs

@jfs J'ai manqué le chemin d'environnement virtuel mais je ne veux pas utiliser autre chose que la ligne shebang pour exécuter ce truc à partir de n'importe quel répertoire. Il ne s'agit pas de courir avec PyCharm. Les développeurs avec PyCharm sauraient également qu'ils ont terminé et sautent à travers des fonctions que je ne pourrais pas faire fonctionner avec aucune solution.
mhstnsc

@mhstnsc un shebang approprié suffit dans de nombreux cas (pointez-le vers le binaire virtualenv python. Tout IDE Python décent devrait prendre en charge un virtualenv.
jfs

9

Je n'ai pas encore la compréhension de la pythonologie nécessaire pour voir la manière prévue de partager du code entre des projets non liés sans un hack d'importation fraternelle / relative. Jusqu'à ce jour, c'est ma solution. Pour examplesou testspour importer des éléments ..\api, cela ressemblerait à:

import sys.path
import os.path
# Import from sibling directory ..\api
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")
import api.api
import api.api_key

Cela vous donnerait toujours le répertoire parent de l'API et vous n'auriez pas besoin de la concaténation "/ .." sys.path.append (os.path.dirname (os.path.dirname (os.path.abspath ( file ))) )
Camilo Sanchez

5

Pour les importations de packages frères, vous pouvez utiliser la méthode insert ou append du module [sys.path] [2] :

if __name__ == '__main__' and if __package__ is None:
    import sys
    from os import path
    sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
    import api

Cela fonctionnera si vous lancez vos scripts comme suit:

python examples/example_one.py
python tests/test_one.py

D'autre part, vous pouvez également utiliser l'importation relative:

if __name__ == '__main__' and if __package__ is not None:
    import ..api.api

Dans ce cas vous devrez lancer votre script avec l' argument '-m' (notez que, dans ce cas, vous ne devez pas donner l' extension '.py' ):

python -m packageName.examples.example_one
python -m packageName.tests.test_one

Bien sûr, vous pouvez mélanger les deux approches, afin que votre script fonctionne quel que soit son nom:

if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
        import api
    else:
        import ..api.api

J'utilisais le framework Click qui n'a pas le __file__global donc j'ai dû utiliser ce qui suit: sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))))Mais cela fonctionne dans n'importe quel répertoire maintenant
GammaGames

2

TLDR

Cette méthode ne nécessite pas de setuptools, de hacks de chemin, d'arguments de ligne de commande supplémentaires ou de spécification du niveau supérieur du package dans chaque fichier de votre projet.

Créez simplement un script dans le répertoire parent de tout ce que vous appelez __main__et exécutez tout à partir de là. Pour plus d'explications, continuez à lire.

Explication

Cela peut être accompli sans pirater un nouveau chemin ensemble, utiliser des arguments de ligne de commande supplémentaires ou ajouter du code à chacun de vos programmes pour reconnaître ses frères.

La raison pour laquelle cela échoue, comme je crois que cela a été mentionné auparavant, c'est que les programmes appelés ont leur __name__ensemble comme __main__. Lorsque cela se produit, le script appelé accepte de se trouver au niveau supérieur du package et refuse de reconnaître les scripts dans les répertoires frères.

Cependant, tout ce qui se trouve sous le niveau supérieur du répertoire reconnaîtra toujours TOUT AUTRE sous le niveau supérieur. Cela signifie que la SEULE chose que vous devez faire pour que les fichiers des répertoires frères se reconnaissent / s'utilisent mutuellement est de les appeler à partir d'un script dans leur répertoire parent.

Proof of Concept Dans un répertoire avec la structure suivante:

.
|__Main.py
|
|__Siblings
   |
   |___sib1
   |   |
   |   |__call.py
   |
   |___sib2
       |
       |__callsib.py

Main.py contient le code suivant:

import sib1.call as call


def main():
    call.Call()


if __name__ == '__main__':
    main()

sib1 / call.py contient:

import sib2.callsib as callsib


def Call():
    callsib.CallSib()


if __name__ == '__main__':
    Call()

et sib2 / callsib.py contient:

def CallSib():
    print("Got Called")

if __name__ == '__main__':
    CallSib()

Si vous reproduisez cet exemple, vous remarquerez que l'appel Main.pyentraînera l' affichage de "Got Called" tel qu'il est défini dans sib2/callsib.py même s'il a sib2/callsib.pyété appelé sib1/call.py. Cependant, si l'on devait appeler directement sib1/call.py(après avoir apporté les modifications appropriées aux importations), il lève une exception. Même s'il a fonctionné lorsqu'il est appelé par le script dans son répertoire parent, il ne fonctionnera pas s'il se croit au niveau supérieur du package.


L'OP a demandé spécifiquement pour « Comment les scripts dans les exampleset testsrépertoires importer à partir du apimodule et être exécuté à partir du commandline ? » Cette réponse ne fonctionnera pas avec la structure de dossiers OP.
np8

Vous n'avez pas besoin du fichier main.py; au lieu d'exécuter la commande python main.pyqui appelle le sib1.call, vous pouvez exécuter python -m sib1.call.
Ersel Er

2

J'ai fait un exemple de projet pour montrer comment j'ai géré cela, qui est en fait un autre hack sys.path comme indiqué ci-dessus. Exemple d'importation de frères Python , qui repose sur:

if __name__ == '__main__': import os import sys sys.path.append(os.getcwd())

Cela semble être assez efficace tant que votre répertoire de travail reste à la racine du projet Python. Si quelqu'un déploie cela dans un environnement de production réel, ce serait formidable de savoir si cela fonctionne également.


Cela ne fonctionne que si vous exécutez à partir du répertoire parent du script
Evpok

1

Vous devez regarder pour voir comment les instructions d'importation sont écrites dans le code associé. Si examples/example_one.pyutilise l'instruction d'importation suivante:

import api.api

... alors il s'attend à ce que le répertoire racine du projet se trouve dans le chemin système.

Le moyen le plus simple de prendre en charge cela sans aucun hacks (comme vous le dites) serait d'exécuter les exemples à partir du répertoire de niveau supérieur, comme ceci:

PYTHONPATH=$PYTHONPATH:. python examples/example_one.py 

Avec Python 2.7.1 je reçois les points suivants: $ python examples/example.py Traceback (most recent call last): File "examples/example.py", line 3, in <module> from api.api import API ImportError: No module named api.api. J'ai aussi la même chose avec import api.api.
zachwill

Mise à jour ma réponse ... vous ne devez ajouter le répertoire courant du chemin d'importation, pas moyen de contourner cela.
AJ.

1

Juste au cas où quelqu'un utilisant Pydev sur Eclipse se retrouverait ici: vous pouvez ajouter le chemin parent du frère (et donc le parent du module appelant) en tant que dossier de bibliothèque externe en utilisant Projet-> Propriétés et en définissant des bibliothèques externes dans le menu de gauche Pydev-PYTHONPATH . Ensuite, vous pouvez importer de votre frère, par exemple from sibling import some_class.


0

Je voulais commenter la solution fournie par np8 mais je n'ai pas assez de réputation, je vais donc simplement mentionner que vous pouvez créer un fichier setup.py exactement comme ils l'ont suggéré, puis le faire à pipenv install --dev -e .partir du répertoire racine du projet pour le transformer en une dépendance modifiable. Ensuite, vos importations absolues fonctionneront, par exemple, from api.api import fooet vous n'aurez pas à vous soucier des installations à l'échelle du système.

Documentation


-1
  1. Projet

1.1 Utilisateur

1.1.1 about.py

1.1.2 init .py

1.2 Technologie

1.2.1 info.py

1.1.2 init .py

Maintenant, si vous souhaitez accéder au module about.py dans le package User , à partir du module info.py du package Tech, vous devez apporter le chemin cmd (dans Windows) à Project, c'est-à-dire ** C: \ Users \ Personal \ Desktop \ Project> ** selon l'exemple de package ci-dessus. Et à partir de ce chemin, vous devez entrer, python -m Package_name.module_name Par exemple pour le package ci-dessus, nous devons faire,

C: \ Users \ Personal \ Desktop \ Project> python -m Tech.info

Points de lutteur

  1. N'utilisez pas l'extension .py après le module d'information, c'est-à-dire python -m Tech.info.py
  2. Entrez ceci, où les packages frères sont dans le même niveau.
  3. -m est le drapeau, pour le vérifier, vous pouvez taper à partir du cmd python --help

-1

pour la question principale:

appeler le dossier frère comme module:

from .. importer le dossier frère

appelez a_file.py depuis le dossier frère comme module:

à partir de ..siblingfolder importer un_fichier

appelez une_fonction dans un fichier dans le dossier frère en tant que module:

from..siblingmodule.a_file import func_name_exists_in_a_file

Le moyen le plus simple.

allez dans le dossier lib / site-packages.

s'il existe un fichier 'easy_install.pth', modifiez-le simplement et ajoutez votre répertoire dans lequel vous avez le script que vous voulez faire comme module.

s'il n'existe pas, créez-en un ... et placez-y le dossier que vous voulez

après l'avoir ajouté ..., python percevra automatiquement ce dossier comme similaire à celui des packages de site et vous pourrez appeler chaque script de ce dossier ou sous-dossier en tant que module.

J'ai écrit ceci sur mon téléphone et j'ai du mal à le configurer pour que tout le monde soit à l'aise à lire.


-3

Tout d'abord, vous devez éviter d'avoir des fichiers avec le même nom que le module lui-même. Cela peut interrompre d'autres importations.

Lorsque vous importez un fichier, l'interpréteur vérifie d'abord le répertoire courant, puis recherche les répertoires globaux.

À l'intérieur examplesou testsvous pouvez appeler:

from ..api import api

Traceback (most recent call last): File "example_one.py", line 3, in <module> from ..api import api ValueError: Attempted relative import in non-package
J'obtiens

2
Oh, alors vous devriez ajouter un __init__.pyfichier au répertoire de niveau supérieur. Sinon, Python ne peut pas le traiter comme un module

8
Ça ne marchera pas. Le problème n'est pas que le dossier parent n'est pas un package, c'est que puisque le module __name__est à la __main__place de package.module, Python ne peut pas voir son package parent, donc ne .pointe vers rien.
Evpok
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.