Self contained Django, or Django like Flask

Posted on Thu 14 May 2020 in misc

Have you thought about spawning Django as easy as Flask?

Imagine that you have a library, which may have a feature that is usable in Django. How to test it?

99% of you would say - make a Django project, put test inside the project, and run django test.

I thought about it, and a voice in my head was screaming: "don't do that. It's messy, it's a lot of unneccesary files". And the voice was right.

After a bit of thinking, I developed such code (see below).

Look! You can instantiate Django like Flask! Few lines and voila - Django is running without all those settings.py, urls.py, views.py, model.py :)

Here is the code:

from typing import List

from django.http import HttpResponse
from django.urls import path
from django.test import Client
import pytest


@pytest.fixture(scope='function')
def view_mappers():
    """ just default, foobar root response """

    def rootview(*_a, **_kwa):
        """ just some rootview """
        return HttpResponse('{"foo": "bar"}', content_type='application/json')

    return [("", rootview)]


@pytest.fixture(scope='function')
def urls(view_mappers: List[tuple]):
    """ fixture which provide urls pseudo module, with urlpatterns and embedded simple view """
    class UrlsPseudoModule:  # pylint: disable=too-few-public-methods
        """ class which emulates URLS of django """

        urlpatterns = [path(k, v) for k, v in view_mappers]

    return UrlsPseudoModule


@pytest.fixture(scope='function')
def configure_django(urls):
    """ configure django engine """
    from django.conf import settings

    if not settings.configured:
        settings.configure(DEBUG=True,
                           MIDDLEWARE=[
                               'django.contrib.sessions.middleware.SessionMiddleware',
                               'your.middleware.to.be.tested'
                           ],
                           SESSION_ENGINE='django.contrib.sessions.backends.signed_cookies')

    settings.ROOT_URLCONF = urls

    import django.apps

    if not django.apps.apps.ready:
        django.setup()


@pytest.fixture(scope='function')
def django_test_client(configure_django):
    """ just django test client """
    return Client()