Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions python/nav/django/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"""Utility methods for django used in NAV"""

from django.core.exceptions import FieldDoesNotExist
from django.http import HttpRequest
from django.urls import reverse
from django.utils.http import urlencode

Expand Down Expand Up @@ -56,6 +57,39 @@ def get_verbose_name(model, lookup):
raise FieldDoesNotExist


def pformat_request(request: HttpRequest, function, *attributes) -> None:
"""View ``request`` via `function``, one line per attribute

Use the ``attributes`` parameter to limit what attributes are inspected.

Also dumps the contents of the dicts ``request.environ``and
``request.META``, one line per value, sorted per key.

The ``function`` must have an input signature compatible with
``logging.Logger.debug()``.

Meant for debugging via logs.

Example usage::

pformat_request(request, logging.getLogger(__name__).debug)
"""
DICT_ATTRIBUTES = ('META', 'environ')

existing_attributes = vars(request).keys()
if attributes:
attributes = set(existing_attributes).intersection(attributes)
else:
attributes = existing_attributes
for attribute in sorted(attributes):
value = getattr(request, attribute)
if attribute in DICT_ATTRIBUTES:
for key in sorted(value.keys()):
function('request.%s: %s: %s', attribute, key, value[key])
else:
function('request.%s: %s', attribute, value)


#
# Django version differentiated helper functions:
#
Expand Down
35 changes: 34 additions & 1 deletion tests/unittests/django/utils_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# -*- coding: utf-8 -*-
from nav.django.utils import get_verbose_name, reverse_with_query
import logging
from unittest import TestCase

from django.test import RequestFactory

from nav.django.utils import get_verbose_name, reverse_with_query, pformat_request

_logger = logging.getLogger(__name__)


def test_verbose_name():
Expand All @@ -13,3 +20,29 @@ def test_verbose_name():
def test_reverse_with_query_should_work_with_unicode():
"""Reveals issues with PY2/PY3 co-compatibility"""
assert reverse_with_query("maintenance-new", roomid="bø-123")


class TestPPRequest(TestCase):
def test_pformat_request_should_log_more_lines_than_there_are_attributes_in_request(
self,
):
r = RequestFactory()
request = r.get('/')
num_request_attributes = len(vars(request))
with self.assertLogs(level=logging.DEBUG) as logs:
pformat_request(request, _logger.debug)
self.assertTrue(len(logs.records) > num_request_attributes)

def test_pformat_request_should_log_nothing_for_nonexistent_attribute(self):
r = RequestFactory()
request = r.get('/')
with self.assertRaises(AssertionError):
with self.assertLogs():
pformat_request(request, _logger.debug, 'doesnotexist-nanana')

def test_pformat_request_should_log_one_line_for_content_type(self):
r = RequestFactory()
request = r.get('/')
with self.assertLogs(level=logging.DEBUG) as logs:
pformat_request(request, _logger.debug, 'content_type')
self.assertEqual(len(logs.records), 1)
Loading