1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

feat: switched to fully custom repr implementation

This commit is contained in:
Keerthi Vasan 2024-06-24 12:26:44 +05:30
parent d68430349e
commit c55d4a1d39
2 changed files with 132 additions and 32 deletions

2
.gitignore vendored
View File

@ -6,7 +6,7 @@
*.pot *.pot
*.py[co] *.py[co]
.tox/ .tox/
venv/ venv*/
__pycache__ __pycache__
MANIFEST MANIFEST
dist/ dist/

View File

@ -1,16 +1,15 @@
import builtins import builtins
import gzip import gzip
import re import re
import reprlib
import secrets import secrets
import unicodedata import unicodedata
from collections import deque from collections import deque
from collections.abc import Sized
from gzip import GzipFile from gzip import GzipFile
from gzip import compress as gzip_compress from gzip import compress as gzip_compress
from html import escape from html import escape
from html.parser import HTMLParser from html.parser import HTMLParser
from io import BytesIO from io import BytesIO
from itertools import islice
from django.core.exceptions import SuspiciousFileOperation from django.core.exceptions import SuspiciousFileOperation
from django.utils.functional import ( from django.utils.functional import (
@ -490,47 +489,148 @@ def _format_lazy(format_string, *args, **kwargs):
format_lazy = lazy(_format_lazy, str) format_lazy = lazy(_format_lazy, str)
class DebugRepr(reprlib.Repr): class DebugRepr:
"""
Modified Reprlib.Repr from Python 3.12 that includes fillvalue customization.
"""
def __init__(self, limit): def __init__(self, limit):
"""Sets maximum print length for all data structures using the given value""" self.indent = 0
self.maxlevel = limit self.maxlevel = 2
self.maxtuple = limit
self.maxlist = limit
self.maxarray = limit
self.maxdict = limit
self.maxset = limit
self.maxfrozenset = limit
self.maxdeque = limit
self.maxstring = limit
self.maxlong = limit
self.maxother = limit
self.limit = limit self.limit = limit
self.fillvalue = "..." def repr(self, x):
self.indent = 2 return self.repr1(x, self.maxlevel)
def repr_str(self, x, level): def repr1(self, x, level):
return "'%s'" % (x[: self.maxstring] + self.gen_trim_msg(len(x))) typename = type(x).__name__
if " " in typename:
parts = typename.split()
typename = "_".join(parts)
if hasattr(self, "repr_" + typename):
return getattr(self, "repr_" + typename)(x, level)
else:
return self.repr_instance(x, level)
def repr_instance(self, x, level): def _join(self, pieces, level):
if self.indent is None:
return ", ".join(pieces)
if not pieces:
return ""
indent = self.indent
if isinstance(indent, int):
if indent < 0:
raise ValueError(f"Repr.indent cannot be negative int (was {indent!r})")
indent *= " "
try:
sep = ", " + (self.maxlevel - level + 1) * indent
except TypeError as error:
raise TypeError(
f"Repr.indent must be a str, int or None, not {type(indent)}"
) from error
return sep.join(("", *pieces))[1 : -len(indent) or None]
def _repr_iterable(self, x, level, left, right, maxiter, trail=""):
n = len(x)
fillvalue = self.gen_trim_msg(n)
if level <= 0 and n:
s = fillvalue
else:
newlevel = level - 1
repr1 = self.repr1
pieces = [repr1(elem, newlevel) for elem in islice(x, maxiter)]
if n > maxiter:
pieces.append(fillvalue)
s = self._join(pieces, level)
if n == 1 and trail and self.indent is None:
right = trail + right
return "%s%s%s" % (left, s, right)
def repr_tuple(self, x, level):
return self._repr_iterable(x, level, "(", ")", self.limit, ",")
def repr_list(self, x, level):
return self._repr_iterable(x, level, "[", "]", self.limit)
def repr_array(self, x, level):
if not x:
return "array('%s')" % x.typecode
header = "array('%s', [" % x.typecode
return self._repr_iterable(x, level, header, "])", self.limit)
def repr_set(self, x, level):
if not x:
return "set()"
x = _possibly_sorted(x)
return self._repr_iterable(x, level, "{", "}", self.limit)
def repr_frozenset(self, x, level):
if not x:
return "frozenset()"
x = _possibly_sorted(x)
return self._repr_iterable(x, level, "frozenset({", "})", self.limit)
def repr_deque(self, x, level):
return self._repr_iterable(x, level, "deque([", "])", self.limit)
def repr_dict(self, x, level):
n = len(x)
if n == 0:
return "{}"
fillvalue = self.gen_trim_msg(n)
if level <= 0:
return "{" + fillvalue + "}"
newlevel = level - 1
repr1 = self.repr1
pieces = []
for key in islice(_possibly_sorted(x), self.limit):
keyrepr = repr1(key, newlevel)
valrepr = repr1(x[key], newlevel)
pieces.append("%s: %s" % (keyrepr, valrepr))
if n > self.limit:
pieces.append(fillvalue)
s = self._join(pieces, level)
return "{%s}" % (s,)
def repr_int(self, x, level):
s = builtins.repr(x) s = builtins.repr(x)
if len(s) > self.maxother: if len(s) > self.limit:
return s[: self.maxother] + self.gen_trim_msg(len(s)) i = max(0, (self.limit - 3) // 2)
j = max(0, self.limit - 3 - i)
s = s[:i] + self.limit + s[len(s) - j :]
return s return s
def repr_instance(self, x, level):
try:
s = builtins.repr(x)
# Bugs in x.__repr__() can cause arbitrary
# exceptions -- then make up something
except Exception:
return "<%s instance at %#x>" % (x.__class__.__name__, id(x))
if len(s) > self.limit:
i = max(0, (self.limit - 3) // 2)
j = max(0, self.limit - 3 - i)
fillvalue = self.gen_trim_msg(len(s))
s = s[:i] + fillvalue + s[len(s) - j :]
return s
def repr_str(self, x, level):
return "'%s'" % (x[: self.limit] + self.gen_trim_msg(len(x)))
def print(self, value): def print(self, value):
if isinstance(value, Sized):
length = len(value)
if length > self.limit:
self.fillvalue = self.gen_trim_msg(length)
else:
self.fillvalue = ""
else:
self.fillvalue = "..."
return self.repr(value) return self.repr(value)
def gen_trim_msg(self, length): def gen_trim_msg(self, length):
if length <= self.limit: if length <= self.limit:
return "" return ""
return "...<trimmed %d bytes string>" % (length - self.limit) return "...<trimmed %d bytes string> " % (length - self.limit)
def _possibly_sorted(x):
# Since not all sequences of items can be sorted and comparison
# functions may raise arbitrary exceptions, return an unsorted
# sequence in that case.
try:
return sorted(x)
except Exception:
return list(x)