Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème d'import dans une arborescence de fichier

Sujet résolu
    3 octobre 2023 à 10:59:42

    Bonjour,

    Je me tourne vers la communauté car je me heurte à un problème d'import que je n'arrive pas à résoudre malgré toutes mes recherches sur la toile.

    Je n'ai pourtant pas l'impression que ma situation soit vraiment extraordinaire, mais vous allez peut-être me dire que c'est ma hiérarchisation qui est mauvaise.

    Voici un exemple de notre architecture :

    Avec l'implémentation montrée ci-dessus, lorsque je lance pytest dans le dossier associé, tout va bien, aucune erreur.

    Mais quand je lance le test dans le dossier monitoring_tests, j'obtiens l'erreur suivante :

    C:\workdir\demo_folder>python monitoring_tests\monitoring_seq1.py
    Traceback (most recent call last):
      File "monitoring_tests\monitoring_seq1.py", line 1, in <module>
        from source_code.feature1 import method1
    ModuleNotFoundError: No module named 'source_code'


    Maintenant, si je change la ligne d'import dans monitoring_seq1.py pour :

    from ..source_code.feature1 import method1

    j'obtiens l'erreur suivante :

    C:\workdir\demo_folder>python monitoring_tests\monitoring_seq1.py
    Traceback (most recent call last):
      File "monitoring_tests\monitoring_seq1.py", line 1, in <module>
        from ..source_code.feature1 import method1
    ImportError: attempted relative import with no known parent package

    J'ai fait beaucoup de recherches, mais je ne crois pas avoir croisé de sujets traitant d'une arborescence similaire. Tous les cas que j'ai vus concernent des import d'un package se trouvant DANS un autre package.

    J'ai bien la solution du fameux "sys.path.append(...)", mais j'ai lu plusieurs fois que c'était pas bien. Et puis ça peut vite amener son lot de soucis si on change de dossiers ou d'environnement.

    Si vous avez des conseils ou des remarques, je suis preneur.

    Merci d'avance !

    Brice

    • Partager sur Facebook
    • Partager sur Twitter
      3 octobre 2023 à 11:14:55

      Je pense que tu vas trouver si je te demande où se trouve les fichiers par rapport au fichier appelant.

      le fichier monitoring_seq1.py se trouve dans "DEMO_FOLDER\monitoring_tests"

      le fichier feature1.py se trouve dans "DEMO_FOLDER\source_code"

      Quel déplacement tu dois faire pour aller du répertoire "DEMO_FOLDER\monitoring_tests" au répertoire "DEMO_FOLDER\source_code" ?

      Dans ton fichier monitoring_seq1.py tu indiques d'aller chercher dans le répertoire "source_code" par rapport à la position du fichier; or pas de répertoire source_code dans le répertoire monitoring_tests

      • Partager sur Facebook
      • Partager sur Twitter
        3 octobre 2023 à 11:37:59

        Oui, je dois remonter.

        Mais c'est justement ce que j'essaie de faire en changeant la ligne d'import et en rajoutant les ".." devant source_code.

        Mais c'est là que j'ai l'erreur qui me dit que je peux pas faire d'import relatif.

        Ce qui est perturbant c'est que VSCode parvient à trouver le chemin (avec l'aide intuitive et l'autocomplétion) dans les deux cas.

        Si je lis un peu entre les lignes, ce que tu suggères c'est que mon script appelant (/demo_folder/monitoring_tests/monitoring_seq1.py) devrait remonter à la racine ?

        Côté Pytest j'ai cette option dans pytest.ini qui me permet de rajouter automatiquement le chemin courant au path, donc la librairie d'import est capable de trouver les chemins des packages.

        Comment faire la même chose pour un script "normal" en gardant cette arborescence ?

        • Partager sur Facebook
        • Partager sur Twitter
          3 octobre 2023 à 12:16:25

          Briçoulefou a écrit:

          Comment faire la même chose pour un script "normal" en gardant cette arborescence ?


          Faire la même chose, c'est créer un fichier ini pour savoir quoi ajouter a sys.path pour que ça marche (avec le code qui va avec)...

          • Partager sur Facebook
          • Partager sur Twitter
            3 octobre 2023 à 13:26:05

            mps a écrit:

            Briçoulefou a écrit:

            Comment faire la même chose pour un script "normal" en gardant cette arborescence ?


            Faire la même chose, c'est créer un fichier ini pour savoir quoi ajouter a sys.path pour que ça marche (avec le code qui va avec)...


            Donc le sys.path.append ne vous choque pas plus que ça ? Je ne retrouve pas le lien de l'article dans lequel l'auteur disait que c'était mal (et je ne me rapelle plus pourquoi).
            • Partager sur Facebook
            • Partager sur Twitter
              3 octobre 2023 à 14:25:09

              Briçoulefou a écrit:

              Donc le sys.path.append ne vous choque pas plus que ça ? Je ne retrouve pas le lien de l'article dans lequel l'auteur disait que c'était mal (et je ne me rapelle plus pourquoi).

              Rien n'est "bien" ou "mal" pour autant que vous arriviez à justifier le pourquoi pour une opération donnée et qu'à la fin, cela reste gérable.

              Il y aura peut être des solutions plus élégantes.... mais (vous vous rendez compte que) ça dépend ce qui a été placé dans la hiérarchie des répertoires (et de ce qui dépend de quoi). Pourquoi ne pas aller étudier quelques projets Python pour voir comment ont été traitées les questions que vous vous posez? Normalement, vous devriez trouver plusieurs solutions chacune avec avantages/inconvénients à considérer pour votre projet.

              • Partager sur Facebook
              • Partager sur Twitter
                3 octobre 2023 à 15:15:07

                Mon souhait principal c'est d'avoir une base de code source que je puisse utiliser depuis deux "environnements" différents:

                - Pytest pour une série de tests qu'on va qualifier de "fonctionnels"

                - des scripts Python classiques qui seront plutôt des tests d'endurance, de monitoring et compagnie (et qui n'ont donc pas vocation à être des "tests")

                • Partager sur Facebook
                • Partager sur Twitter
                  3 octobre 2023 à 15:56:52

                  modifier sys.path est une solution... il y en a d'autres et si ça vous intéresse vous savez où chercher.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    3 octobre 2023 à 17:26:04

                    Je fouille je fouille et je crois que je commence à cerner un peu plus mon problème, que j'ai peut-être mal explicité au début.

                    Dans mon exemple, mon souhait est, outre le fait de vouloir une base de code réutilisable dans différents environnements, de rester à la racine du dossier et d'appeler mon script dans le dossier monitoring_tests.

                    De ce fait, j'ai beau mettre des __init__.py partout avec le sys.path.append(), ceux ci ne seront jamais exécutés et le script (module) monitoring_seq1.py ne s'exécutera jamais dans un environnement auquel j'aurai ajouté mon chemin courant, donc il ne sera jamais capable de trouver les modules/packages autour.

                    Dans un cas je lance la commande :

                    pytest pytest_tests

                    qui va récupérer les fichiers dans le dossier "pytest_tests", et également appliquer la configuration dans le pytest.ini (donc ajouter le chemin courant au path).

                    Dans l'autre cas je lance la commande :

                    python monitoring_tests\monitoring_seq1.py

                    et du coup je n'ai à aucun moment d'exécution d'un bout de code qui me rajoute le chemin courant au path de l'environnement en cours (à moins bien sur de l'ajouter dans le fichier monitoring_seq1.py, mais cela sous-entendrait de l'ajouter à chaque nouveau fichier dans ce dossier).

                    Au final mon interrogation est de savoir où placer le sys.path.append pour pouvoir appeler mes scripts dans le dossier "monitoring_tests" depuis la racine du dépôt.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      3 octobre 2023 à 18:04:43

                      Briçoulefou a écrit:

                      Au final mon interrogation est de savoir où placer le sys.path.append pour pouvoir appeler mes scripts dans le dossier "monitoring_tests" depuis la racine du dépôt.


                      La réponse est dans le tuto qui vient avec python au chapitre qui parle des dossiers de recherche des modules. Et comme il n'y a pas 36 (bons) tutos qui parlent des modules, bizarre que vous ne l'ayez pas lu...
                      • Partager sur Facebook
                      • Partager sur Twitter
                        4 octobre 2023 à 9:48:24

                        Bonjour,

                        J'avais déjà lu ce tutoriel, et je l'ai à l'instant relu en détail en voyant votre réponse.

                        Pardon de ne pas avoir les mêmes compétences que vous en Python. La réponse vous semble peut-être évidente, mais j'ai beau essayer tous les élements de ce tutoriel qui me semblent en relation avec mon problème, sans succès.

                        J'ai beau tourner la chose dans tous les sens, je ne parviens pas à appeler mon script tel quel :

                        python monitoring_tests\monitoring_seq1.py

                        sans mettre le fameux sys.path.append('.') au début du fichier monitoring_seq1.py (ce que je cherche à éviter et à factoriser justement).

                        Si je déplace mon script à la racine du dossier et que je fais:

                        python monitoring_seq1.py

                        ça fonctionne.

                        Du moment que le script à appeler est dans un sous répertoire (donc un package), il n'est plus capable de trouver les modules et packages autour de lui sans le sys.path.append.

                        -
                        Edité par Briçoulefou 4 octobre 2023 à 10:05:21

                        • Partager sur Facebook
                        • Partager sur Twitter
                          4 octobre 2023 à 12:16:23

                          Briçoulefou a écrit:

                          J'ai beau tourner la chose dans tous les sens, je ne parviens pas à appeler mon script tel quel :

                          python monitoring_tests\monitoring_seq1.py

                          sans mettre le fameux sys.path.append('.') au début du fichier monitoring_seq1.py (ce que je cherche à éviter et à factoriser justement).

                          Pour modifier le chemin dans lequel import ira chercher les modules, il  y a aussi la variable du shell PYTHONPATH (qui évite de modifier son code pour y modifier sys.path).

                           Briçoulefou a écrit:

                          Pardon de ne pas avoir les mêmes compétences que vous en Python.

                          lire une documentation qui parle de PYTHONPATH en passant à côté n'a pas grand chose à voir avec Python.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            4 octobre 2023 à 12:22:00

                            Je viens de trouver ma réponse. Ou du moins un moyen d'arriver à mes fins très simplement.

                            Je pense que ma principale lacune est sur la méconnaissance de l'environnement d'exécution de Python et comment il gère ses librairies d'import et compagnie. J'aurais eu beau lire la doc de PYTHONPATH je n'aurai pas compris ce qui me manquait sans voir un exemple concret, justement à cause de la lacune sus-mentionnée.

                            Il me suffit de lancer mon script de la manière suivante:

                            python -m monitoring_tests.monitoring_seq1

                            J'essayais depuis le début de faire ça avec un \ à la place du .

                            J'espère que cela pourra servir à d'autres.

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Problème d'import dans une arborescence de fichier

                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                            • Editeur
                            • Markdown