web-dev-qa-db-fra.com

Python importe pour les tests utilisant nose - quelle est la meilleure pratique pour importer des modules au-dessus du paquet actuel

C'est une question qui est fréquemment posée sous différentes formes, et obtient souvent des réponses "lol tu ne le fais pas correctement". Je suis sûr que c'est parce qu'il y a un scénario de bon sens que les gens (y compris moi) essaient d'utiliser comme implémentation, et la solution n'est pas évidente (si vous ne l'avez pas déjà fait).

Accepterait une réponse qui "laisse voler la bouteille".

Donné

project/
    __init__.py
    /code
        __init__.py
        sut.py
    /tests
        __init__.py
        test_sut.py

Où tests_sut.py commence:

import code.sut

L'exécution de nosetests dans le répertoire racine conduit à:

ImportError: No module named code.sut

Avenues parcourues:

a) faire un parent en utilisant

from ..code import sut

b) ajouter la racine du projet à PYTHONPATH

c) utiliser le

sys.path.append

pour ajouter le chemin .. avant les importations au début de chaque module de test.

d) n'oubliez pas de faire un

setup.py 

sur le projet pour installer les modules dans les sites-packages avant d'exécuter les tests.


Donc, l'exigence est d'avoir des tests situés sous la racine du package de test qui ont accès au projet. Chacun des éléments ci-dessus ne me semble pas "naturel", s'est avéré problématique ou semble être un travail trop dur!

Dans Java cela fonctionne, mais essentiellement à force de votre outil de construction/IDE placer toutes vos classes sur le chemin de classe. Peut-être que le problème est que j'attends " magie "de Python? A noté dans les Flask tests de webframework, option d) semble être préféré.

En tout état de cause, les déclarations ci-dessous recommandant une solution préférée élimineraient le sentiment de "contre nature" dans le mien.

64
leonigmig

Vous avez déjà assez bien répondu à votre question. D (installer à l'emplacement du système) est préférable pour le code distribuable. J'utilise habituellement C (modifier sys.path) parce que je ne veux pas d'installations à l'échelle du système de mes centaines de bibliothèques personnalisées. En théorie, A (importation relative) semble plus agréable, mais il y a des cas où il échoue. B (PYTHONPATH) est sorti, vraiment uniquement à des fins de test à mon avis.

Cela résume à peu près toutes les options. L'option que vous préférez (Python sait par magie où chercher) n'est vraiment pas une solution viable car elle peut conduire à des résultats imprévisibles, tels que la recherche automatique de bibliothèques à partir de projets non liés.

À mon avis, la meilleure chose à faire est de mettre ceci au point (s) d'entrée de votre programme:

import sys, os
sys.path = [os.path.abspath(os.path.dirname(__file__))] + sys.path
10
Luke

J'ai eu le même problème et j'ai trouvé un réponse dans une question connexe pour moi.

Supprimez simplement le __init__.py à la racine du projet.

44
cnu

Je sais qu'il y a une réponse vérifiée et je pense toujours que c'est une bonne raison de partager d'autres alternatives :)

Il y a un nez-pathmunge vous donnant un contrôle pour définir sys.path en appelant nosestests.

4
Drake Guan