File: templates.py

package info (click to toggle)
python-pytest-djangoapp 1.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 396 kB
  • sloc: python: 1,116; makefile: 114; sh: 6
file content (160 lines) | stat: -rw-r--r-- 4,273 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import re
from typing import Union
from unittest import mock

import pytest
from django import VERSION
from django.template.base import Template
from django.template.context import Context, RenderContext

if False:  # pragma: nocover
    from django.contrib.auth.models import AbstractUser  # noqa
    from django.http import HttpRequest


RE_TAG_VALUES = re.compile('>([^<]+)<')


@pytest.fixture
def template_strip_tags():
    """Allows HTML tags strip from string.

    To be used with `template_render_tag` fixture to easy result assertions.

    Example::

        def test_this(template_strip_tags):
            stripped = template_strip_tags('<b>some</b>')

    :param html: HTML to strin tags from
    :param joiner: String to join tags contents. Default: |

    """
    def template_strip_tags_(html: str, joiner: str = '|') -> str:

        result = []
        for match in RE_TAG_VALUES.findall(html):
            match = match.strip()
            if match:
                result.append(match)

        return joiner.join(result)

    return template_strip_tags_


@pytest.fixture
def template_context(request_get, user_create):
    """Creates template context object.

    To be used with `template_render_tag` fixture.

    Example::

        def test_this(template_context):
            context = template_context({'somevar': 'someval'})

    :param context_dict: Template context. If not set empty context is used.

    :param request: Expects HttpRequest or string.
        String is used as a path for GET-request.

    :param current_app:

    :param user: User instance to associate request with.
        Defaults to a new anonymous user.
        If string is passed, it is considered to be


    """
    def template_context_(
        context_dict: dict = None,
        *,
        request: 'HttpRequest' = None,
        current_app: str = '',
        user: Union[str, 'AbstractUser'] = 'anonymous'
    ) -> Context:

        context_dict = context_dict or {}

        if user and isinstance(user, str):
            if user == 'anonymous':
                user = user_create(anonymous=True)
            else:
                user = user_create(attributes={'username': user})

        if not request or isinstance(request, str):
            request = request_get(request, user=user)

        context_updater = {
            'request': request,
        }

        if user:
            context_updater['user'] = user

        context_dict.update(context_updater)

        context = Context(context_dict)
        contribute_to_context(context, current_app)

        return context

    return template_context_


@pytest.fixture
def template_render_tag():
    """Renders a template tag from a given library by its name.

    Example::

        def test_this(template_render_tag):
            rendered = template_render_tag('library_name', 'mytag arg1 arg2')

    :param library: Template tags library name to load tag from.

    :param tag_str: Tag string itself. As used in templates, but without {% %}.

    :param context: Template context object. If not set,
        empty context object is used.

    """
    def template_render_tag_(library: str, tag_str: str, context: Union[dict, Context] = None) -> str:
        context = context or {}

        if not isinstance(context, Context):
            context = Context(context)

        string = f'{{% load {library} %}}{{% {tag_str} %}}'

        template = Template(string)
        contribute_to_context(context, template=template)

        if VERSION >= (1, 11):
            # Prevent "TypeError: 'NoneType' object is not iterable" in  get_exception_info
            template.nodelist[1].token.position = (0, 0)

        return template.render(context)

    return template_render_tag_


def contribute_to_context(context: Context, current_app: str = '', template: Template = None):
    template = template or mock.MagicMock()

    if VERSION >= (1, 8):
        template.engine.string_if_invalid = ''

    context.template = template

    if VERSION >= (1, 11):
        context.render_context = RenderContext()

    if VERSION >= (1, 10):
        match = mock.MagicMock()
        match.app_name = current_app
        context.resolver_match = match

    else:
        context._current_app = current_app