so far so good

all tests pass
This commit is contained in:
Jeremy Langley 2022-02-13 07:56:58 -08:00
parent efc7c1d664
commit e7ecbf92c4
18 changed files with 59 additions and 80 deletions

View File

@ -140,7 +140,7 @@ if markdown is not None and pygments is not None:
code = m.group(2).replace('\t', ' ')
code = pygments.highlight(code, lexer, self.formatter)
code = code.replace('\n\n', '\n&nbsp;\n').replace('\n', '<br />').replace('\\@', '@')
return '\n\n%s\n\n' % code
return f'\n\n{code}\n\n'
ret = self.pattern.sub(repl, "\n".join(lines))
return ret.split("\n")

View File

@ -41,7 +41,7 @@ def api_view(http_method_names=None):
# api_view applied with eg. string instead of list of strings
assert isinstance(http_method_names, (list, tuple)), \
'@api_view expected a list of strings, received %s' % type(http_method_names).__name__
f'@api_view expected a list of strings, received {type(http_method_names).__name__}'
allowed_methods = set(http_method_names) | {'options'}
WrappedAPIView.http_method_names = [method.lower() for method in allowed_methods]
@ -199,7 +199,7 @@ class MethodMapper(dict):
def _map(self, method, func):
assert method not in self, (
"Method '%s' has already been mapped to '.%s'." % (method, self[method]))
f"Method '{method}' has already been mapped to '.{self[method]}'.")
assert func.__name__ != self.action.__name__, (
"Method mapping does not behave like the property decorator. You "
"cannot use the same method name for each mapping declaration.")

View File

@ -84,10 +84,8 @@ class ErrorDetail(str):
return not self.__eq__(other)
def __repr__(self):
return 'ErrorDetail(string=%r, code=%r)' % (
str(self),
self.code,
)
return f"ErrorDetail(string='{str(self)}', code='{self.code}')"
def __hash__(self):
return hash(str(self))

View File

@ -280,7 +280,7 @@ class CreateOnlyDefault:
return self.default
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, repr(self.default))
return f'{self.__class__.__name__}({repr(self.default)})'
class CurrentUserDefault:
@ -290,7 +290,7 @@ class CurrentUserDefault:
return serializer_field.context['request'].user
def __repr__(self):
return '%s()' % self.__class__.__name__
return f'{self.__class__.__name__}()'
class SkipField(Exception):

View File

@ -236,9 +236,9 @@ class OrderingFilter(BaseFilterBackend):
(field.source.replace('.', '__') or field_name, field.label)
for field_name, field in serializer_class(context=context).fields.items()
if (
not getattr(field, 'write_only', False) and
not field.source == '*' and
field.source not in model_property_names
not getattr(field, 'write_only', False) and
not field.source == '*' and
field.source not in model_property_names
)
]
@ -294,9 +294,9 @@ class OrderingFilter(BaseFilterBackend):
'param': self.ordering_param,
}
for key, label in self.get_valid_fields(queryset, view, context):
options.append((key, '%s - %s' % (label, _('ascending'))))
options.append(('-' + key, '%s - %s' % (label, _('descending'))))
context['options'] = options
options.append((key, f'{label} - {_("ascending")}'))
options.append(('-' + key, f'{label} - {_("descending")}'))
context['options'] = options
return context
def to_html(self, request, queryset, view):

View File

@ -61,9 +61,9 @@ class GenericAPIView(views.APIView):
(Eg. return a list of items that is specific to the user)
"""
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
f"'{self.__class__.__name__}' should either include a `queryset` attribute, "
f"or override the `get_queryset()` method."
)
queryset = self.queryset
@ -120,9 +120,8 @@ class GenericAPIView(views.APIView):
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
f"'{self.__class__.__name__}' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class

View File

@ -64,7 +64,7 @@ class JSONParser(BaseParser):
parse_constant = json.strict_constant if self.strict else None
return json.load(decoded_stream, parse_constant=parse_constant)
except ValueError as exc:
raise ParseError('JSON parse error - %s' % str(exc))
raise ParseError(f'JSON parse error - {str(exc)}')
class FormParser(BaseParser):
@ -109,7 +109,7 @@ class MultiPartParser(BaseParser):
data, files = parser.parse()
return DataAndFiles(data, files)
except MultiPartParserError as exc:
raise ParseError('Multipart form parse error - %s' % str(exc))
raise ParseError(f'Multipart form parse error - {str(exc)}')
class FileUploadParser(BaseParser):

View File

@ -46,6 +46,7 @@ class Hyperlink(str):
We use this for hyperlinked URLs that may render as a named link
in some contexts, or render as a plain URL in others.
"""
def __new__(cls, url, obj):
ret = super().__new__(cls, url)
ret.obj = obj
@ -70,11 +71,12 @@ class PKOnlyObject:
instance, but still want to return an object with a .pk attribute,
in order to keep the same interface as a regular model instance.
"""
def __init__(self, pk):
self.pk = pk
def __str__(self):
return "%s" % self.pk
return f"{self.pk}"
# We assume that 'validators' are intended for the child serializer,
@ -376,9 +378,9 @@ class HyperlinkedRelatedField(RelatedField):
def to_representation(self, value):
assert 'request' in self.context, (
"`%s` requires the request in the serializer"
f"`{self.__class__.__name__}` requires the request in the serializer"
" context. Add `context={'request': request}` when instantiating "
"the serializer." % self.__class__.__name__
"the serializer."
)
request = self.context['request']
@ -409,9 +411,9 @@ class HyperlinkedRelatedField(RelatedField):
if value in ('', None):
value_string = {'': 'the empty string', None: 'None'}[value]
msg += (
" WARNING: The value of the field on the model instance "
"was %s, which may be why it didn't match any "
"entries in your URL conf." % value_string
" WARNING: The value of the field on the model instance "
"was %s, which may be why it didn't match any "
"entries in your URL conf." % value_string
)
raise ImproperlyConfigured(msg % self.view_name)

View File

@ -197,7 +197,7 @@ class TemplateHTMLRenderer(BaseRenderer):
return self.resolve_template(template_names)
except Exception:
# Fall back to using eg '404 Not Found'
body = '%d %s' % (response.status_code, response.status_text.title())
body = f'{response.status_code} {response.status_text.title()}'
template = engines['django'].from_string(body)
return template
@ -414,9 +414,9 @@ class BrowsableAPIRenderer(BaseRenderer):
render_style = getattr(renderer, 'render_style', 'text')
assert render_style in ['text', 'binary'], 'Expected .render_style ' \
'"text" or "binary", but got "%s"' % render_style
f'"text" or "binary", but got "{render_style}"'
if render_style == 'binary':
return '[%d bytes of binary content]' % len(content)
return f'[{len(content)} bytes of binary content]'
return content.decode('utf-8') if isinstance(content, bytes) else content
@ -660,9 +660,9 @@ class BrowsableAPIRenderer(BaseRenderer):
response_headers = OrderedDict(sorted(response.items()))
renderer_content_type = ''
if renderer:
renderer_content_type = '%s' % renderer.media_type
renderer_content_type = f'{renderer.media_type}'
if renderer.charset:
renderer_content_type += ' ;%s' % renderer.charset
renderer_content_type += f' ;{renderer.charset}'
response_headers['Content-Type'] = renderer_content_type
if getattr(view, 'paginator', None) and view.paginator.display_page_controls:

View File

@ -154,7 +154,7 @@ class Request:
assert isinstance(request, HttpRequest), (
'The `request` argument must be an instance of '
'`django.http.HttpRequest`, not `{}.{}`.'
.format(request.__class__.__module__, request.__class__.__name__)
.format(request.__class__.__module__, request.__class__.__name__)
)
self._request = request
@ -180,11 +180,8 @@ class Request:
self.authenticators = (forced_auth,)
def __repr__(self):
return '<%s.%s: %s %r>' % (
self.__class__.__module__,
self.__class__.__name__,
self.method,
self.get_full_path())
return f'<{self.__class__.__module__}.{self.__class__.__name__}: ' \
f"{self.method} '{self.get_full_path()}'>"
def _default_negotiator(self):
return api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()

View File

@ -1105,20 +1105,17 @@ class ModelSerializer(Serializer):
if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)):
raise TypeError(
'The `fields` option must be a list or tuple or "__all__". '
'Got %s.' % type(fields).__name__
f'Got {type(fields).__name__}.'
)
if exclude and not isinstance(exclude, (list, tuple)):
raise TypeError(
'The `exclude` option must be a list or tuple. Got %s.' %
type(exclude).__name__
f'The `exclude` option must be a list or tuple. Got {type(exclude).__name__}.'
)
assert not (fields and exclude), (
"Cannot set both 'fields' and 'exclude' options on "
"serializer {serializer_class}.".format(
serializer_class=self.__class__.__name__
)
f"Cannot set both 'fields' and 'exclude' options on "
f"serializer {self.__class__.__name__}."
)
assert not (fields is None and exclude is None), (

View File

@ -91,7 +91,7 @@ class SimpleRateThrottle(BaseThrottle):
try:
return self.THROTTLE_RATES[self.scope]
except KeyError:
msg = "No default throttle rate set for '%s' scope" % self.scope
msg = f"No default throttle rate set for '{self.scope}' scope"
raise ImproperlyConfigured(msg)
def parse_rate(self, rate):

View File

@ -9,7 +9,7 @@ def _get_format_path_converter(suffix_kwarg, allowed):
if len(allowed) == 1:
allowed_pattern = allowed[0]
else:
allowed_pattern = '(?:%s)' % '|'.join(allowed)
allowed_pattern = f'(?:{"|".join(allowed)})'
suffix_pattern = r"\.%s/?" % allowed_pattern
else:
suffix_pattern = r"\.[a-z0-9]+/?"
@ -99,7 +99,7 @@ def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
if len(allowed) == 1:
allowed_pattern = allowed[0]
else:
allowed_pattern = '(%s)' % '|'.join(allowed)
allowed_pattern = f'({"|".join(allowed)})'
suffix_pattern = r'\.(?P<%s>%s)/?$' % (suffix_kwarg, allowed_pattern)
else:
suffix_pattern = r'\.(?P<%s>[a-z0-9]+)/?$' % suffix_kwarg
@ -107,6 +107,6 @@ def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
converter_name, suffix_converter = _get_format_path_converter(suffix_kwarg, allowed)
register_converter(suffix_converter, converter_name)
suffix_route = '<%s:%s>' % (converter_name, suffix_kwarg)
suffix_route = f'<{converter_name}:{suffix_kwarg}>'
return apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required, suffix_route)

View File

@ -48,7 +48,7 @@ class UniqueValidator:
"""
Filter the queryset to all instances matching the given attribute.
"""
filter_kwargs = {'%s__%s' % (field_name, self.lookup): value}
filter_kwargs = {f'{field_name}__{self.lookup}': value}
return qs_filter(queryset, **filter_kwargs)
def exclude_current_instance(self, queryset, instance):
@ -74,10 +74,7 @@ class UniqueValidator:
raise ValidationError(self.message, code='unique')
def __repr__(self):
return '<%s(queryset=%s)>' % (
self.__class__.__name__,
smart_repr(self.queryset)
)
return f'<{self.__class__.__name__}(queryset={smart_repr(self.queryset)})>'
class UniqueTogetherValidator:
@ -160,11 +157,7 @@ class UniqueTogetherValidator:
raise ValidationError(message, code='unique')
def __repr__(self):
return '<%s(queryset=%s, fields=%s)>' % (
self.__class__.__name__,
smart_repr(self.queryset),
smart_repr(self.fields)
)
return f'<{self.__class__.__name__}(queryset={smart_repr(self.queryset)}, fields={smart_repr(self.fields)})>'
class ProhibitSurrogateCharactersValidator:
@ -231,12 +224,8 @@ class BaseUniqueForValidator:
}, code='unique')
def __repr__(self):
return '<%s(queryset=%s, field=%s, date_field=%s)>' % (
self.__class__.__name__,
smart_repr(self.queryset),
smart_repr(self.field),
smart_repr(self.date_field)
)
return f'<{self.__class__.__name__}(queryset={smart_repr(self.queryset)}, ' \
f'field={smart_repr(self.field)}, date_field={smart_repr(self.date_field)})>'
class UniqueForDateValidator(BaseUniqueForValidator):
@ -246,11 +235,10 @@ class UniqueForDateValidator(BaseUniqueForValidator):
value = attrs[self.field]
date = attrs[self.date_field]
filter_kwargs = {}
filter_kwargs[field_name] = value
filter_kwargs['%s__day' % date_field_name] = date.day
filter_kwargs['%s__month' % date_field_name] = date.month
filter_kwargs['%s__year' % date_field_name] = date.year
filter_kwargs = {field_name: value,
f'{date_field_name}__day': date.day,
f'{date_field_name}__month': date.month,
f'{date_field_name}__year': date.year}
return qs_filter(queryset, **filter_kwargs)
@ -263,7 +251,7 @@ class UniqueForMonthValidator(BaseUniqueForValidator):
filter_kwargs = {}
filter_kwargs[field_name] = value
filter_kwargs['%s__month' % date_field_name] = date.month
filter_kwargs[f'{date_field_name}__month'] = date.month
return qs_filter(queryset, **filter_kwargs)
@ -274,7 +262,5 @@ class UniqueForYearValidator(BaseUniqueForValidator):
value = attrs[self.field]
date = attrs[self.date_field]
filter_kwargs = {}
filter_kwargs[field_name] = value
filter_kwargs['%s__year' % date_field_name] = date.year
filter_kwargs = {field_name: value, f'{date_field_name}__year': date.year}
return qs_filter(queryset, **filter_kwargs)

View File

@ -197,7 +197,7 @@ class ViewSetMixin:
for action in actions:
try:
url_name = '%s-%s' % (self.basename, action.url_name)
url_name = f'{self.basename}-{action.url_name}'
url = reverse(url_name, self.args, self.kwargs, request=self.request)
view = self.__class__(**action.kwargs)
action_urls[view.get_view_name()] = url

View File

@ -70,9 +70,9 @@ class ErrorDetailTests(TestCase):
def test_repr(self):
assert repr(ErrorDetail('msg1')) == \
'ErrorDetail(string={!r}, code=None)'.format('msg1')
f"ErrorDetail(string='msg1', code='None')"
assert repr(ErrorDetail('msg1', 'code')) == \
'ErrorDetail(string={!r}, code={!r})'.format('msg1', 'code')
f"ErrorDetail(string='msg1', code='code')"
def test_str(self):
assert str(ErrorDetail('msg1')) == 'msg1'

View File

@ -208,7 +208,7 @@ class SearchFilterTests(TestCase):
def as_sql(self, compiler, connection):
sql, params = compiler.compile(self.lhs)
return "trim(%s, 'a')" % sql, params
return f"trim({sql}, 'a')", params
with register_lookup(CharField, TrimA):
# Search including `a`

View File

@ -13,7 +13,7 @@ class MockObject:
'%s=%s' % (key, value)
for key, value in sorted(self._kwargs.items())
])
return '<MockObject %s>' % kwargs_str
return f'<MockObject {kwargs_str}>'
class MockQueryset: