ModuleNotFoundError: No module named " "

96 Views Asked by At

Here is the context: I am working on Django. I started coding features but stopped to set up the first unit tests.

I wanted to test my CustomUser class located in JoBooking.models.py in the test_models.py file. JoBooking is an app I created in my Django project.

So I did the import from JoParis.JoBookings.models import CustomUser.

When I run python manage.py test or pytest in the terminal, I encounter this error: ModuleNotFoundError: No module named 'JoParis.JoBooking'

I have configured the application (JoBooking) in settings.py... but nothing works.

The init.py files are present in the packages.

I did a simple test to check if the URL of my application returns an HTTP 200 response, and the test works, but I have to remove the import from JoParis.JoBookings.models import CustomUser. So the test file is found, but the problem comes from the import when I want to test my models.

I'm stuck. I don't understand this error. ModuleNotFoundError: No module named Just explain me what is this error please. Thanks

In test_models.py

from django.test import TestCase
from ...JoBooking.models import CustomUser


# test inscription avec données valides et obligatoires
class TestCreateUser(TestCase):
    def test_create_user(self):
        user = CustomUser.objects.create_user(
            email='[email protected]',
            password='password',
            username='',
            first_name='user',
            last_name='test',
            is_superuser=False,
            is_staff=False
        )
        assert CustomUser.objects.filter(email='[email protected]').exists()  # verifie si dans la BDD
        assert user.first_name == 'user'
        assert user.last_name == 'test'
        assert user.is_superuser is False  # verifie si attribut par défaut pris en compte
        assert user.is_staff is False


# test inscription  avec données non valides
# test connexion user avec True data
# test connexion user avec False data


# test qui verifie  http response = 200
class TestUrl(TestCase):
    def test_my_view(self):
        response = self.client.get('http://127.0.0.1:8000/')
        self.assertEqual(response.status_code, 200)

in setting.py

from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = x

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'JoBooking',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'JoParis.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "JoBooking/templates/JoBooking")],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'JoParis.wsgi.application'

# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            "read_default_file": 'C:\\Users\\murhe\\OneDrive\\Bureau\\EXAM JO\\my.cnf.txt',
        },
    }
}

# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/

LANGUAGE_CODE = 'fr-fr'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/

STATIC_URL = '/static/'

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL = 'JoBooking.CustomUser'

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'JoBooking.authbackends.EmailAuthBackend',
]

The error message


: (venv) PS C:\Users\murhe\PycharmProjects\StudiProject\JoParis> pytest
====================================================================== test session starts =======================================================================
platform win32 -- Python 3.11.1, pytest-8.0.1, pluggy-1.4.0
django: version: 5.0.2, settings: JoParis.settings (from ini)
rootdir: C:\Users\murhe\PycharmProjects\StudiProject\JoParis
configfile: pytest.ini
plugins: django-4.8.0
collected 0 items / 2 errors                                                                                                                                      

============================================================================= ERRORS ============================================================================= 
________________________________________________________ ERROR collecting JoBooking/tests/test_models.py _________________________________________________________ 
ImportError while importing test module 'C:\Users\murhe\PycharmProjects\StudiProject\JoParis\JoBooking\tests\test_models.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
E   ModuleNotFoundError: No module named 'JoParis.JoBooking'
_________________________________________________________ ERROR collecting JoBooking/tests/test_views.py _________________________________________________________ 
ImportError while importing test module 'C:\Users\murhe\PycharmProjects\StudiProject\JoParis\JoBooking\tests\test_views.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
..\..\..\AppData\Local\Programs\Python\Python311\Lib\importlib\__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
E   ModuleNotFoundError: No module named 'JoParis.JoBooking'
======================================================================== warnings summary ======================================================================== 
..\venv\Lib\site-packages\_pytest\config\__init__.py:1396
  C:\Users\murhe\PycharmProjects\StudiProject\venv\Lib\site-packages\_pytest\config\__init__.py:1396: PytestConfigWarning: Unknown config option: PYTHONPATH       

    self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
==================================================================== short test summary info ===================================================================== 
ERROR JoBooking/tests/test_models.py
ERROR JoBooking/tests/test_views.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 2 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
================================================================== 1 warning, 2 errors in 0.68s ===============

in views.py '''

from django.shortcuts import render, redirect
from django.contrib.auth import login, logout
from .forms import Connexion
from django.contrib.auth.forms import UserCreationForm
from .models import CustomUser, Offre, Reservation, Commande
from .authbackends import EmailAuthBackend
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
import uuid

# méthode pour créer un formulaire d'inscription (utilisation du formulaire émit par django par défaut)
class CustomSignupForm(UserCreationForm):
    class Meta:
        model = CustomUser  # ici on spécifie qu'on veut ce modèle personnalisé
        fields = ('first_name', 'last_name', 'email')
        #note : le password est automatiquement intégré dans ce form


# view pour la page d'accueil
def index(request):
    return render(request, 'JoBooking/index.html')


# view pour la page des offres
def offres(request):
    list_offres = Offre.objects.all()  # affiche toutes les offres  = plan solo,duo,family ou autre
    context = {'offres': list_offres}
    return render(request, 'JoBooking/offres.html', context)


# view pour la page d'inscription
def inscription(request):
    context = {}  # stockage données  lors du rendu de page

    if request.method == 'POST':  # vérification methode de la requête est POST = formulaire soumis
        form = CustomSignupForm(request.POST)  # création formulaire avec données POST
        if form.is_valid():  # vérification  de la validité des données
            user = form.save()  # sauvegarde dans la BDD
            user.cle_inscription = uuid.uuid4().hex
            user.save()

            return redirect('inscription_reussie')  # redirection de l'utilisateur vers une autre page
        else:
            context['errors'] = form.errors  # erreur de validation

    form = CustomSignupForm()  # nouvelle page d'inscription vide  donc sans POST
    context['form'] = form
    return render(request, 'JoBooking/inscription.html', context=context)  # renvoie page d'inscription


# view pour l'inscripion réussie d'un user
def inscription_reussie(request):
    return render(request, 'inscription_reussie.html')


# view pour la page de connexion
def connexion(request):
    message = ""
    if request.method == 'POST':
        form = Connexion(request.POST)  # création formulaire avec données envoyées via POST
        if form.is_valid():  # vérification de la validité des données
            email = form.cleaned_data['email']  # données nettoyées et récupérées
            password = form.cleaned_data['password']

            custom_auth = EmailAuthBackend()  # implémentation de l'authentification personnalisée
            user = custom_auth.authenticate(request, email=email, password=password)  # appel de la méthode authenticate

            # email = request.POST.get('email')
            # password = request.POST.get('password')

            if user is not None and password is not None:  # signification : si l'user a été trouvée ...
                login(request, user, backend='JoBooking.authbackends.EmailAuthBackend')  # ya 2 backends d'auth
                message = f'Bienvenue {user.first_name} ! Vous êtes connecté.'
                return redirect('/')  # redirige vers la page d'acceuil
            else:
                message = 'Identifiants non valides.'
                return render(request, 'connexion.html',
                              context={'message': message})  # user non trouvé, donc retourne page connexion
    else:
        form = Connexion()

    return render(request, 'connexion.html', context={'form': form, 'message': message})


# méthode pour que les users se déconnecte
def deconnexion(request):
    logout(request)
    return redirect('index')


# méthode pour ajouter à réservation. ( réservation c'est le panier. J'ai volontairement choisi ce terme)
def ajouter_reservation(request, offre_id):
    user = request.user
    offre = get_object_or_404(Offre, id=offre_id)  # ici on récupère l'offre si inexistante,erreur 404
    reservation, _ = Reservation.objects.get_or_create(user=user)  # récupération du panier
    commande, created = Commande.objects.get_or_create(user=user,
                                                       offre=offre)  # récupération commande

    if created:  # exemple:  une offre n'est pas dans la commande donc elle sera crée
        reservation.commandes.add(commande)
        reservation.save()
    else:  # l'offre est deja dans la commande donc on augmente la quantité
        commande.quantity += 1
        commande.save()
    return redirect('offres')


#  renvoie  à la page de reservation (c'est la page panier, après avoir réserver)
@login_required(login_url='connexion')  # connexion nécessaire pour avoir accès a cette page
def reservation(request):
    reservation = get_object_or_404(Reservation, user=request.user)
    return render(request, 'reservation.html', context={
        'commandes': reservation.commandes.all()})  # affiche tous les éléments qu'ya dans la réservation


# methode pour annuler une réservation au complet
def annulation(request):
    user_reservation = Reservation.objects.get(user=request.user)
    if user_reservation:  # si elle existe
        user_reservation.commandes.all().delete()
        user_reservation.delete()  # suppression de tout ce qu'y a dans la réservation qu'on supprime ensuite

    return redirect('index')  # retourne vers la page d'accueil


def payer(request):
    reservation = request.user.reservation

    # génération de billets (combinaison des deux clés générées , qr code, nom acheteur + logo ;date de l'evement )

    # augmentation de ventes de Offre selon la quantité achetée
    for commande in reservation.commandes.all():
        offre = commande.offre  # récupration du plan dans la commande
        offre.ventes += commande.quantity
        offre.save()
    # paiement dans Reservation devient TRUE (initialement à FALSE)
    reservation.paiement = True
    reservation.save()

    # génération de clé unique pour paiment seulement si payer.
    if reservation.paiement == True:
        cle_paiement = uuid.uuid4().hex
        reservation.cle_paiement = cle_paiement
        reservation.save()

    # le panier (réservation ) est réinitialisé
    reservation.commandes.clear()
    # Renvoie à la page de remerciement où on peut telecharger billet
    return redirect('remerciements')


def remerciements(request):
    return render(request, 'remerciements.html')

'''

in test_views.py

'''

from django.test import TestCase
from ...JoBooking.models import CustomUser


class TestUrl(TestCase):
    def test_my_view(self):
        response = self.client.get('http://127.0.0.1:8000/')
        self.assertEqual(response.status_code, 200)

'''

another way to test

(venv) PS C:\Users\murhe\PycharmProjects\StudiProject\JoParis> python manage.py test JoBooking
Found 1 test(s).
System check identified no issues (0 silenced).
E
======================================================================
ERROR: JoParis.JoBooking (unittest.loader._FailedTest.JoParis.JoBooking)
----------------------------------------------------------------------
ImportError: Failed to import test module: JoParis.JoBooking
Traceback (most recent call last):
  File "C:\Users\murhe\AppData\Local\Programs\Python\Python311\Lib\unittest\loader.py", line 440, in _find_test_path
    package = self._get_module_from_name(name)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\murhe\AppData\Local\Programs\Python\Python311\Lib\unittest\loader.py", line 350, in _get_module_from_name
    __import__(name)
ModuleNotFoundError: No module named 'JoParis.JoBooking'
1

There are 1 best solutions below

31
Pycm On

General answer :-

Try like below.

from JoBookings.models import CustomUser 

You should use relative paths to import from other scripts. In JoParis.JoBookings.models

JoParis is the folder name/project name

JoBookings is the app name /app folder name(inside project folder)

models is the python file name(inside app folder).

Which all are relative to current (importing statement) file.

So, to import like above, JoParis should be a sub folder from the current test script.


Insight upon new info regarding the problem :-

For C:\Users\murhe\PycharmProjects\StudiProject\JoParis\JoBooking\tests\test_models.py location, try like below.

from ...JoBookings.models import CustomUser 

More info :-

link 1

link 2


Django tests :-

Look here for how to run tests