Skip to content

Add pyupgrade to pre-commit hooks #9682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 9, 2025
Merged
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
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ repos:
hooks:
- id: codespell
exclude: locale|kickstarter-announcement.md|coreapi-0.1.1.js

- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
args: ["--py39-plus", "--keep-percent-format"]
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ def handle(self, *args, **options):
username)
)
self.stdout.write(
'Generated token {} for user {}'.format(token.key, username))
f'Generated token {token.key} for user {username}')
6 changes: 3 additions & 3 deletions rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def get_attribute(instance, attrs):
# If we raised an Attribute or KeyError here it'd get treated
# as an omitted field in `Field.get_attribute()`. Instead we
# raise a ValueError to ensure the exception is not masked.
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
raise ValueError(f'Exception raised in callable attribute "{attr}"; original exception was: {exc}')

return instance

Expand Down Expand Up @@ -1103,7 +1103,7 @@ def to_representation(self, value):
if self.localize:
return localize_input(quantized)

return '{:f}'.format(quantized)
return f'{quantized:f}'

def quantize(self, value):
"""
Expand Down Expand Up @@ -1861,7 +1861,7 @@ def __init__(self, method_name=None, **kwargs):
def bind(self, field_name, parent):
# The method name defaults to `get_{field_name}`.
if self.method_name is None:
self.method_name = 'get_{field_name}'.format(field_name=field_name)
self.method_name = f'get_{field_name}'

super().bind(field_name, parent)

Expand Down
2 changes: 1 addition & 1 deletion rest_framework/negotiation.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def select_renderer(self, request, renderers, format_suffix=None):
full_media_type = ';'.join(
(renderer.media_type,) +
tuple(
'{}={}'.format(key, value)
f'{key}={value}'
for key, value in media_type_wrapper.params.items()
)
)
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def _queryset(self, view):
if hasattr(view, 'get_queryset'):
queryset = view.get_queryset()
assert queryset is not None, (
'{}.get_queryset() returned None'.format(view.__class__.__name__)
f'{view.__class__.__name__}.get_queryset() returned None'
)
return queryset
return view.queryset
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def rendered_content(self):
content_type = self.content_type

if content_type is None and charset is not None:
content_type = "{}; charset={}".format(media_type, charset)
content_type = f"{media_type}; charset={charset}"
elif content_type is None:
content_type = media_type
self['Content-Type'] = content_type
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/schemas/coreapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def get_available_key(self, preferred_key):
current_val = self.methods_counter[preferred_key]
self.methods_counter[preferred_key] += 1

key = '{}_{}'.format(preferred_key, current_val)
key = f'{preferred_key}_{current_val}'
if key not in self:
return key

Expand Down
4 changes: 2 additions & 2 deletions rest_framework/schemas/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def get_schema(self, request=None, public=False):
continue
if components_schemas[k] == components[k]:
continue
warnings.warn('Schema component "{}" has been overridden with a different value.'.format(k))
warnings.warn(f'Schema component "{k}" has been overridden with a different value.')

components_schemas.update(components)

Expand Down Expand Up @@ -644,7 +644,7 @@ def get_response_serializer(self, path, method):
return self.get_serializer(path, method)

def get_reference(self, serializer):
return {'$ref': '#/components/schemas/{}'.format(self.get_component_name(serializer))}
return {'$ref': f'#/components/schemas/{self.get_component_name(serializer)}'}

def get_request_body(self, path, method):
if method not in ('PUT', 'PATCH', 'POST'):
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/utils/field_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_unique_validators(field_name, model_field):
"""
Returns a list of UniqueValidators that should be applied to the field.
"""
field_set = set([field_name])
field_set = {field_name}
conditions = {
c.condition
for c in model_field.model._meta.constraints
Expand Down
2 changes: 1 addition & 1 deletion tests/schemas/test_coreapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ def _verify_cbv_links(self, loc, url, methods=None, suffixes=None):

for method, suffix in zip(methods, suffixes):
if suffix is not None:
key = '{}_{}'.format(method, suffix)
key = f'{method}_{suffix}'
else:
key = method
assert loc[key].url == url
Expand Down
4 changes: 2 additions & 2 deletions tests/schemas/test_managementcommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ def test_renders_openapi_json_schema(self):

def test_accepts_custom_schema_generator(self):
call_command('generateschema',
'--generator_class={}.{}'.format(__name__, CustomSchemaGenerator.__name__),
f'--generator_class={__name__}.{CustomSchemaGenerator.__name__}',
stdout=self.out)
out_json = yaml.safe_load(self.out.getvalue())
assert out_json == CustomSchemaGenerator.SCHEMA

def test_writes_schema_to_file_on_parameter(self):
fd, path = tempfile.mkstemp()
try:
call_command('generateschema', '--file={}'.format(path), stdout=self.out)
call_command('generateschema', f'--file={path}', stdout=self.out)
# nothing on stdout
assert not self.out.getvalue()

Expand Down
4 changes: 2 additions & 2 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ def test_get_full_details_with_throttling(self):

exception = Throttled(wait=2)
assert exception.get_full_details() == {
'message': 'Request was throttled. Expected available in {} seconds.'.format(2),
'message': f'Request was throttled. Expected available in {2} seconds.',
'code': 'throttled'}

exception = Throttled(wait=2, detail='Slow down!')
assert exception.get_full_details() == {
'message': 'Slow down! Expected available in {} seconds.'.format(2),
'message': f'Slow down! Expected available in {2} seconds.',
'code': 'throttled'}


Expand Down
10 changes: 5 additions & 5 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ def test_valid_inputs(self, *args):
"""
for input_value, expected_output in get_items(self.valid_inputs):
assert self.field.run_validation(input_value) == expected_output, \
'input value: {}'.format(repr(input_value))
f'input value: {repr(input_value)}'

def test_invalid_inputs(self, *args):
"""
Expand All @@ -672,12 +672,12 @@ def test_invalid_inputs(self, *args):
with pytest.raises(serializers.ValidationError) as exc_info:
self.field.run_validation(input_value)
assert exc_info.value.detail == expected_failure, \
'input value: {}'.format(repr(input_value))
f'input value: {repr(input_value)}'

def test_outputs(self, *args):
for output_value, expected_output in get_items(self.outputs):
assert self.field.to_representation(output_value) == expected_output, \
'output value: {}'.format(repr(output_value))
f'output value: {repr(output_value)}'


# Boolean types...
Expand Down Expand Up @@ -1422,7 +1422,7 @@ class TestDateField(FieldValues):
outputs = {
datetime.date(2001, 1, 1): '2001-01-01',
'2001-01-01': '2001-01-01',
str('2016-01-10'): '2016-01-10',
'2016-01-10': '2016-01-10',
None: None,
'': None,
}
Expand Down Expand Up @@ -1489,7 +1489,7 @@ class TestDateTimeField(FieldValues):
datetime.datetime(2001, 1, 1, 13, 00): '2001-01-01T13:00:00Z',
datetime.datetime(2001, 1, 1, 13, 00, tzinfo=utc): '2001-01-01T13:00:00Z',
'2001-01-01T00:00:00': '2001-01-01T00:00:00',
str('2016-01-10T00:00:00'): '2016-01-10T00:00:00',
'2016-01-10T00:00:00': '2016-01-10T00:00:00',
None: None,
'': None,
}
Expand Down
2 changes: 1 addition & 1 deletion tests/test_generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def test_put_to_filtered_out_instance(self):
"""
data = {'text': 'foo'}
filtered_out_pk = BasicModel.objects.filter(text='filtered out')[0].pk
request = factory.put('/{}'.format(filtered_out_pk), data, format='json')
request = factory.put(f'/{filtered_out_pk}', data, format='json')
response = self.view(request, pk=filtered_out_pk).render()
assert response.status_code == status.HTTP_404_NOT_FOUND

Expand Down
10 changes: 5 additions & 5 deletions tests/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ def test_invalid_limit(self):
content = self.get_paginated_content(queryset)
next_limit = self.pagination.default_limit
next_offset = self.pagination.default_limit
next_url = 'http://testserver/?limit={}&offset={}'.format(next_limit, next_offset)
next_url = f'http://testserver/?limit={next_limit}&offset={next_offset}'
assert queryset == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert content.get('next') == next_url

Expand All @@ -549,7 +549,7 @@ def test_zero_limit(self):
content = self.get_paginated_content(queryset)
next_limit = self.pagination.default_limit
next_offset = self.pagination.default_limit
next_url = 'http://testserver/?limit={}&offset={}'.format(next_limit, next_offset)
next_url = f'http://testserver/?limit={next_limit}&offset={next_offset}'
assert queryset == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
assert content.get('next') == next_url

Expand All @@ -565,9 +565,9 @@ def test_max_limit(self):
max_limit = self.pagination.max_limit
next_offset = offset + max_limit
prev_offset = offset - max_limit
base_url = 'http://testserver/?limit={}'.format(max_limit)
next_url = base_url + '&offset={}'.format(next_offset)
prev_url = base_url + '&offset={}'.format(prev_offset)
base_url = f'http://testserver/?limit={max_limit}'
next_url = base_url + f'&offset={next_offset}'
prev_url = base_url + f'&offset={prev_offset}'
assert queryset == list(range(51, 66))
assert content.get('next') == next_url
assert content.get('previous') == prev_url
Expand Down
4 changes: 2 additions & 2 deletions tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def setUp(self):
'delete': f('delete', model_name)
}
for perm in perms.values():
perm = '{}.{}'.format(app_label, perm)
perm = f'{app_label}.{perm}'
assign_perm(perm, everyone)
everyone.user_set.add(*users.values())

Expand Down Expand Up @@ -718,7 +718,7 @@ def has_object_permission(self, request, view, obj):
assert hasperm is False

def test_operand_holder_is_hashable(self):
assert hash((permissions.IsAuthenticated & permissions.IsAdminUser))
assert hash(permissions.IsAuthenticated & permissions.IsAdminUser)

def test_operand_holder_hash_same_for_same_operands_and_operator(self):
first_operand_holder = (
Expand Down
2 changes: 1 addition & 1 deletion tests/test_relations_pk.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ def test_one_to_one_when_primary_key(self):
source = OneToOnePKSourceSerializer(data={'name': 'source-2', 'target': target_pk})
# Then: The source is valid with the serializer
if not source.is_valid():
self.fail("Expected OneToOnePKTargetSerializer to be valid but had errors: {}".format(source.errors))
self.fail(f"Expected OneToOnePKTargetSerializer to be valid but had errors: {source.errors}")
# Then: Saving the serializer creates a new object
new_source = source.save()
# Then: The new object has the same pk as the target object
Expand Down
4 changes: 2 additions & 2 deletions tests/test_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ def test_u2028_u2029(self):
obj = {'should_escape': '\u2028\u2029'}
renderer = JSONRenderer()
content = renderer.render(obj, 'application/json')
self.assertEqual(content, '{"should_escape":"\\u2028\\u2029"}'.encode())
self.assertEqual(content, b'{"should_escape":"\\u2028\\u2029"}')


class AsciiJSONRendererTests(TestCase):
Expand All @@ -421,7 +421,7 @@ class AsciiJSONRenderer(JSONRenderer):
obj = {'countries': ['United Kingdom', 'France', 'España']}
renderer = AsciiJSONRenderer()
content = renderer.render(obj, 'application/json')
self.assertEqual(content, '{"countries":["United Kingdom","France","Espa\\u00f1a"]}'.encode())
self.assertEqual(content, b'{"countries":["United Kingdom","France","Espa\\u00f1a"]}')


# Tests for caching issue, #346
Expand Down
2 changes: 1 addition & 1 deletion tests/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def test_if_there_is_charset_specified_on_renderer_it_gets_appended(self):
"""
headers = {"HTTP_ACCEPT": RendererC.media_type}
resp = self.client.get('/', **headers)
expected = "{}; charset={}".format(RendererC.media_type, RendererC.charset)
expected = f"{RendererC.media_type}; charset={RendererC.charset}"
self.assertEqual(expected, resp['Content-Type'])

def test_content_type_set_explicitly_on_response(self):
Expand Down
12 changes: 6 additions & 6 deletions tests/test_routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,9 @@ def _test_list_and_detail_route_decorators(self, viewset):
url_path = endpoint.url_path

if method_name.startswith('list_'):
assert route.url == '^{{prefix}}/{0}{{trailing_slash}}$'.format(url_path)
assert route.url == f'^{{prefix}}/{url_path}{{trailing_slash}}$'
else:
assert route.url == '^{{prefix}}/{{lookup}}/{0}{{trailing_slash}}$'.format(url_path)
assert route.url == f'^{{prefix}}/{{lookup}}/{url_path}{{trailing_slash}}$'
# check method to function mapping
if method_name.endswith('_post'):
method_map = 'post'
Expand Down Expand Up @@ -488,14 +488,14 @@ class TestRegexUrlPath(URLPatternsTestCase, TestCase):

def test_regex_url_path_list(self):
kwarg = '1234'
response = self.client.get('/regex/list/{}/'.format(kwarg))
response = self.client.get(f'/regex/list/{kwarg}/')
assert response.status_code == 200
assert json.loads(response.content.decode()) == {'kwarg': kwarg}

def test_regex_url_path_detail(self):
pk = '1'
kwarg = '1234'
response = self.client.get('/regex/{}/detail/{}/'.format(pk, kwarg))
response = self.client.get(f'/regex/{pk}/detail/{kwarg}/')
assert response.status_code == 200
assert json.loads(response.content.decode()) == {'pk': pk, 'kwarg': kwarg}

Expand Down Expand Up @@ -557,14 +557,14 @@ def test_delete(self):

def test_list_extra_action(self):
kwarg = 1234
response = self.client.get('/path/list/{}/'.format(kwarg))
response = self.client.get(f'/path/list/{kwarg}/')
assert response.status_code == 200
assert json.loads(response.content.decode()) == {'kwarg': kwarg}

def test_detail_extra_action(self):
pk = '1'
kwarg = 1234
response = self.client.get('/path/{}/detail/{}/'.format(pk, kwarg))
response = self.client.get(f'/path/{pk}/detail/{kwarg}/')
assert response.status_code == 200
assert json.loads(response.content.decode()) == {'pk': pk, 'kwarg': kwarg}

Expand Down
4 changes: 2 additions & 2 deletions tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,14 @@ def test_max_value_validation_serializer_fails(self):

def test_max_value_validation_success(self):
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
request = factory.patch('/{}'.format(obj.pk), {'number_value': 98}, format='json')
request = factory.patch(f'/{obj.pk}', {'number_value': 98}, format='json')
view = UpdateMaxValueValidationModel().as_view()
response = view(request, pk=obj.pk).render()
assert response.status_code == status.HTTP_200_OK

def test_max_value_validation_fail(self):
obj = ValidationMaxValueValidatorModel.objects.create(number_value=100)
request = factory.patch('/{}'.format(obj.pk), {'number_value': 101}, format='json')
request = factory.patch(f'/{obj.pk}', {'number_value': 101}, format='json')
view = UpdateMaxValueValidationModel().as_view()
response = view(request, pk=obj.pk).render()
assert response.content == b'{"number_value":["Ensure this value is less than or equal to 100."]}'
Expand Down
Loading