pythondjangodjango-tests

AttributeError: 'NoneType' object has no attribute 'rsplit'


I'm getting AttributeError: 'NoneType' object has no attribute 'rsplit' error when trying to run this code self.client.get("/"). Test running in Docker on Windows 10 machine. Other simple model tests are running good, just like the application itself. Also tried running this test in another project, and there wasn't any problems. Feel free to ask for more information if needed.
The whole error:

Traceback (most recent call last):
  File "/usr/src/app/app/tests/test.py", line 5, in test_test
    resp = self.client.get("/")
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 836, in get
    response = super().get(path, data=data, secure=secure, **extra)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 424, in get
    return self.generic(
           ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 541, in generic
    return self.request(**r)
           ^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 805, in request
    response = self.handler(environ)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/test/client.py", line 140, in __call__
    self.load_middleware()
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 61, in load_middleware
    mw_instance = middleware(adapted_handler)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/middleware.py", line 105, in __init__
    self.add_files(self.static_root, prefix=self.static_prefix)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 107, in add_files
    self.update_files_dictionary(root, prefix)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 119, in update_files_dictionary
    self.add_file_to_dictionary(url, path, stat_cache=stat_cache)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 130, in add_file_to_dictionary
    static_file = self.get_static_file(path, url, stat_cache=stat_cache)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 202, in get_static_file
    self.add_cache_headers(headers, path, url)
  File "/usr/local/lib/python3.11/site-packages/whitenoise/base.py", line 223, in add_cache_headers
    if self.immutable_file_test(path, url):
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/middleware.py", line 177, in immutable_file_test
    static_url = self.get_static_url(name_without_hash)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/whitenoise/middleware.py", line 200, in get_static_url
    return staticfiles_storage.url(name)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/utils/functional.py", line 266, in inner
    self._setup()
  File "/usr/local/lib/python3.11/site-packages/django/contrib/staticfiles/storage.py", line 496, in _setup
    self._wrapped = get_storage_class(settings.STATICFILES_STORAGE)()
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/core/files/storage.py", line 419, in get_storage_class
    return import_string(import_path or settings.DEFAULT_FILE_STORAGE)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/utils/module_loading.py", line 25, in import_string
    module_path, class_name = dotted_path.rsplit(".", 1)
                              ^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'rsplit'

The whole test file:

from django.test import TestCase

class TestTest(TestCase):
    def test_test(self):
        resp = self.client.get("/")

docker-compose.yml file (all secure data is only for local development):

version: "3.9"

services:
  web:
    build: .
    command: python /code/manage.py runserver 0.0.0.0:8080
    volumes:
      - .:/code
    ports:
      - 8080:8080
      - 9999:9999
    depends_on:
      - db
  db:
    image: postgres:14
    environment:
      POSTGRES_USER: postgres
      POSTGRES_DB: blog
      POSTGRES_PASSWORD: 7895
    ports:
      - 5432:5432
    volumes:
      - postgres_data:/var/lib/postgresql/data/

volumes:
  postgres_data:

All packages are up to date, using Python 3.11.2 and Django 4.1.7.
Settings.py file in case you will need it:

"""
Django settings for blogapp project.

Generated by 'django-admin startproject' using Django 4.1.3.

For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""


from pathlib import Path
import os

from dotenv import find_dotenv, load_dotenv
import dj_database_url

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

load_dotenv(find_dotenv())

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

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv("DEBUG", "0").lower() in ["true", "t", "1"]

ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS").split(" ")
CSRF_TRUSTED_ORIGINS = os.getenv("CSRF_TRUSTED_ORIGINS").split(" ")


# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "whitenoise.runserver_nostatic",
    "django.contrib.staticfiles",
    "app.apps.AppConfig",
    "tinymce",
    "storages",
]

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


ROOT_URLCONF = "blogapp.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR.joinpath("templates")],
        "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 = "blogapp.wsgi.application"


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

DATABASES = {"default": dj_database_url.config()}

# Password validation
# https://docs.djangoproject.com/en/4.1/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",
    },
]


TINYMCE_JS_URL = "https://cdn.tiny.cloud/1/jys86spz5w4zp7jbfbr16eorvcw4sx1j2yg6q26namjws4do/tinymce/5/tinymce.min.js"
TINYMCE_COMPRESSOR = True


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

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


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

STATIC_URL = "static/"
MEDIA_URL = "/media/"
MEDIA_ROOT = Path(BASE_DIR).joinpath("upload")
STATIC_ROOT = BASE_DIR / "static/"

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

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# S3 Bucket
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = os.getenv("AWS_STORAGE_BUCKET_NAME")
DEFAULT_FILE_STORAGE = os.getenv("DEFAULT_FILE_STORAGE")
AWS_S3_FILE_OVERWRITE = os.getenv("AWS_S3_FILE_OVERWRITE", "0").lower() in ["true", "t", "1"]
AWS_DEFAULT_ACL = os.getenv("AWS_DEFAULT_ACL")
STATICFILES_STORAGE = os.getenv("STATICFILES_STORAGE")
AWS_S3_REGION_NAME = os.getenv("AWS_S3_REGION_NAME")

Solution

  • Looking at the traceback, it seems that settings.DEFAULT_FILE_STORAGE is None.
    It seems you're getting it from a dotenv. Are you sure it is defined inside and your dotenv is found ?