Skip to content

Commit 9ced3be

Browse files
authored
Introduce flake8 bugbear plugin (#1101)
* Introduce flake8 bugbear * Enable optional bugbear warnings
1 parent 55bd312 commit 9ced3be

18 files changed

+88
-75
lines changed

example/settings/dev.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
REST_FRAMEWORK = {
6969
"PAGE_SIZE": 5,
7070
"EXCEPTION_HANDLER": "rest_framework_json_api.exceptions.exception_handler",
71-
"DEFAULT_PAGINATION_CLASS": "rest_framework_json_api.pagination.JsonApiPageNumberPagination",
71+
"DEFAULT_PAGINATION_CLASS": "rest_framework_json_api.pagination.JsonApiPageNumberPagination", # noqa: B950
7272
"DEFAULT_PARSER_CLASSES": (
7373
"rest_framework_json_api.parsers.JSONParser",
7474
"rest_framework.parsers.FormParser",

example/tests/integration/test_non_paginated_responses.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
2929
"blogHyperlinked": {
3030
"links": {
3131
"related": "http://testserver/entries/1/blog",
32-
"self": "http://testserver/entries/1/relationships/blog_hyperlinked",
32+
"self": "http://testserver/entries/1/relationships/blog_hyperlinked", # noqa: B950
3333
}
3434
},
3535
"authors": {
@@ -43,7 +43,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
4343
"commentsHyperlinked": {
4444
"links": {
4545
"related": "http://testserver/entries/1/comments",
46-
"self": "http://testserver/entries/1/relationships/comments_hyperlinked",
46+
"self": "http://testserver/entries/1/relationships/comments_hyperlinked", # noqa: B950
4747
}
4848
},
4949
"suggested": {
@@ -63,7 +63,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
6363
"featuredHyperlinked": {
6464
"links": {
6565
"related": "http://testserver/entries/1/featured",
66-
"self": "http://testserver/entries/1/relationships/featured_hyperlinked",
66+
"self": "http://testserver/entries/1/relationships/featured_hyperlinked", # noqa: B950
6767
}
6868
},
6969
"tags": {"data": [], "meta": {"count": 0}},
@@ -84,7 +84,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
8484
"blogHyperlinked": {
8585
"links": {
8686
"related": "http://testserver/entries/2/blog",
87-
"self": "http://testserver/entries/2/relationships/blog_hyperlinked",
87+
"self": "http://testserver/entries/2/relationships/blog_hyperlinked", # noqa: B950
8888
}
8989
},
9090
"authors": {
@@ -98,7 +98,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
9898
"commentsHyperlinked": {
9999
"links": {
100100
"related": "http://testserver/entries/2/comments",
101-
"self": "http://testserver/entries/2/relationships/comments_hyperlinked",
101+
"self": "http://testserver/entries/2/relationships/comments_hyperlinked", # noqa: B950
102102
}
103103
},
104104
"suggested": {
@@ -118,7 +118,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
118118
"featuredHyperlinked": {
119119
"links": {
120120
"related": "http://testserver/entries/2/featured",
121-
"self": "http://testserver/entries/2/relationships/featured_hyperlinked",
121+
"self": "http://testserver/entries/2/relationships/featured_hyperlinked", # noqa: B950
122122
}
123123
},
124124
"tags": {"data": [], "meta": {"count": 0}},

example/tests/integration/test_pagination.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_pagination_with_single_entry(single_entry, client):
2929
"blogHyperlinked": {
3030
"links": {
3131
"related": "http://testserver/entries/1/blog",
32-
"self": "http://testserver/entries/1/relationships/blog_hyperlinked",
32+
"self": "http://testserver/entries/1/relationships/blog_hyperlinked", # noqa: B950
3333
}
3434
},
3535
"authors": {
@@ -43,7 +43,7 @@ def test_pagination_with_single_entry(single_entry, client):
4343
"commentsHyperlinked": {
4444
"links": {
4545
"related": "http://testserver/entries/1/comments",
46-
"self": "http://testserver/entries/1/relationships/comments_hyperlinked",
46+
"self": "http://testserver/entries/1/relationships/comments_hyperlinked", # noqa: B950
4747
}
4848
},
4949
"suggested": {
@@ -63,7 +63,7 @@ def test_pagination_with_single_entry(single_entry, client):
6363
"featuredHyperlinked": {
6464
"links": {
6565
"related": "http://testserver/entries/1/featured",
66-
"self": "http://testserver/entries/1/relationships/featured_hyperlinked",
66+
"self": "http://testserver/entries/1/relationships/featured_hyperlinked", # noqa: B950
6767
}
6868
},
6969
"tags": {

example/tests/integration/test_polymorphism.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_polymorphism_on_detail_relations(single_company, client):
3333
def test_polymorphism_on_included_relations(single_company, client):
3434
response = client.get(
3535
reverse("company-detail", kwargs={"pk": single_company.pk})
36-
+ "?include=current_project,future_projects,current_art_project,current_research_project"
36+
+ "?include=current_project,future_projects,current_art_project,current_research_project" # noqa: B950
3737
)
3838
content = response.json()
3939
assert (
@@ -169,14 +169,14 @@ def test_invalid_type_on_polymorphic_model(client):
169169
try:
170170
assert (
171171
content["errors"][0]["detail"]
172-
== "The resource object's type (invalidProjects) is not the type that constitute the "
172+
== "The resource object's type (invalidProjects) is not the type that constitute the " # noqa: B950
173173
"collection represented by the endpoint (one of [researchProjects, artProjects])."
174174
)
175175
except AssertionError:
176176
# Available type list order isn't enforced
177177
assert (
178178
content["errors"][0]["detail"]
179-
== "The resource object's type (invalidProjects) is not the type that constitute the "
179+
== "The resource object's type (invalidProjects) is not the type that constitute the " # noqa: B950
180180
"collection represented by the endpoint (one of [artProjects, researchProjects])."
181181
)
182182

example/tests/test_filters.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -482,15 +482,15 @@ def test_search_keywords(self):
482482
"blog": {"data": {"type": "blogs", "id": "1"}},
483483
"blogHyperlinked": {
484484
"links": {
485-
"self": "http://testserver/entries/7/relationships/blog_hyperlinked", # noqa: E501
485+
"self": "http://testserver/entries/7/relationships/blog_hyperlinked", # noqa: B950
486486
"related": "http://testserver/entries/7/blog",
487487
}
488488
},
489489
"authors": {"meta": {"count": 0}, "data": []},
490490
"comments": {"meta": {"count": 0}, "data": []},
491491
"commentsHyperlinked": {
492492
"links": {
493-
"self": "http://testserver/entries/7/relationships/comments_hyperlinked", # noqa: E501
493+
"self": "http://testserver/entries/7/relationships/comments_hyperlinked", # noqa: B950
494494
"related": "http://testserver/entries/7/comments",
495495
}
496496
},
@@ -515,14 +515,14 @@ def test_search_keywords(self):
515515
},
516516
"suggestedHyperlinked": {
517517
"links": {
518-
"self": "http://testserver/entries/7/relationships/suggested_hyperlinked", # noqa: E501
518+
"self": "http://testserver/entries/7/relationships/suggested_hyperlinked", # noqa: B950
519519
"related": "http://testserver/entries/7/suggested/",
520520
}
521521
},
522522
"tags": {"data": [], "meta": {"count": 0}},
523523
"featuredHyperlinked": {
524524
"links": {
525-
"self": "http://testserver/entries/7/relationships/featured_hyperlinked", # noqa: E501
525+
"self": "http://testserver/entries/7/relationships/featured_hyperlinked", # noqa: B950
526526
"related": "http://testserver/entries/7/featured",
527527
}
528528
},
@@ -550,7 +550,7 @@ def test_search_multiple_keywords(self):
550550
1. For each keyword, search the 4 search_fields for a match and then get the result
551551
set which is the union of all results for the given keyword.
552552
2. Intersect those results sets such that *all* keywords are represented.
553-
See `example/fixtures/blogentry.json` for the test content that the searches are based on.
553+
See `example/fixtures/blogentry.json` for what test content the searches are based on.
554554
The searches test for both direct entries and related blogs across multiple fields.
555555
"""
556556
for searches in (

example/tests/test_views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,8 @@ def test_if_returns_error_on_bad_endpoint_name(self):
562562
expected = [
563563
{
564564
"detail": (
565-
"The resource object's type (bad) is not the type that constitute the collection "
566-
"represented by the endpoint (blogs)."
565+
"The resource object's type (bad) is not the type that constitute the "
566+
"collection represented by the endpoint (blogs)."
567567
),
568568
"source": {"pointer": "/data"},
569569
"status": "409",

example/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,8 @@ class NoPagination(JsonApiPageNumberPagination):
144144

145145
class NonPaginatedEntryViewSet(EntryViewSet):
146146
pagination_class = NoPagination
147-
# override the default filter backends in order to test QueryParameterValidationFilter without
148-
# breaking older usage of non-standard query params like `page_size`.
147+
# override the default filter backends in order to test QueryParameterValidationFilter
148+
# without breaking older usage of non-standard query params like `page_size`.
149149
filter_backends = (
150150
QueryParameterValidationFilter,
151151
OrderingFilter,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
black==22.10.0
22
flake8==5.0.4
3+
flake8-bugbear==22.10.27
34
flake8-isort==5.0.0
45
isort==5.10.1

rest_framework_json_api/django_filters/backends.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ class DjangoFilterBackend(DjangoFilterBackend):
4444
- A related resource path
4545
can be used:
4646
47-
``?filter[inventory.item.partNum]=123456`` (where `inventory.item` is the relationship path)
47+
``?filter[inventory.item.partNum]=123456``
48+
49+
where `inventory.item` is the relationship path.
4850
4951
If you are also using rest_framework.filters.SearchFilter you'll want to customize
5052
the name of the query parameter for searching to make sure it doesn't conflict

rest_framework_json_api/exceptions.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ def rendered_with_json_api(view):
1818
def exception_handler(exc, context):
1919
# Import this here to avoid potential edge-case circular imports, which
2020
# crashes with:
21-
# "ImportError: Could not import 'rest_framework_json_api.parsers.JSONParser' for API setting
22-
# 'DEFAULT_PARSER_CLASSES'. ImportError: cannot import name 'exceptions'.'"
21+
# "ImportError: Could not import 'rest_framework_json_api.parsers.JSONParser' for
22+
# API setting 'DEFAULT_PARSER_CLASSES'.
23+
# ImportError: cannot import name 'exceptions'.'"
2324
#
2425
# Also see: https://github.com/django-json-api/django-rest-framework-json-api/issues/158
2526
from rest_framework.views import exception_handler as drf_exception_handler

rest_framework_json_api/metadata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def get_field_info(self, field):
113113
field_info["type"] = self.type_lookup[field]
114114

115115
try:
116-
serializer_model = getattr(serializer.Meta, "model")
116+
serializer_model = serializer.Meta.model
117117
field_info["relationship_type"] = self.relation_type_lookup[
118118
getattr(serializer_model, field.field_name)
119119
]

rest_framework_json_api/parsers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ def parse_data(self, result, parser_context):
8585
from rest_framework_json_api.views import RelationshipView
8686

8787
if isinstance(view, RelationshipView):
88-
# We skip parsing the object as JSON:API Resource Identifier Object and not a regular
89-
# Resource Object
88+
# We skip parsing the object as JSON:API Resource Identifier Object and not
89+
# a regular Resource Object
9090
if isinstance(data, list):
9191
for resource_identifier_object in data:
9292
if not (

rest_framework_json_api/relations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def get_links(self, obj=None, lookup_field="pk"):
123123
# AuthorViewSet.as_view({'get': 'retrieve_related'}))
124124
# 2. url(r'^authors/(?P<author_pk>[^/.]+)/bio/$',
125125
# AuthorBioViewSet.as_view({'get': 'retrieve'}))
126-
# So, if related_link_url_kwarg == 'pk' it will add 'related_field' parameter to reverse()
126+
# So, if related_link_url_kwarg == 'pk' it adds 'related_field' parameter to reverse()
127127
if self.related_link_url_kwarg == "pk":
128128
related_kwargs = self_kwargs
129129
else:

rest_framework_json_api/schemas/openapi.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,11 @@ class SchemaGenerator(drf_openapi.SchemaGenerator):
115115
"uniqueItems": True,
116116
},
117117
# A RelationshipView uses a ResourceIdentifierObjectSerializer (hence the name
118-
# ResourceIdentifierObject returned by get_component_name()) which serializes type and
119-
# id. These can be lists or individual items depending on whether the relationship is
120-
# toMany or toOne so offer both options since we are not iterating over all the
121-
# possible {related_field}'s but rather rendering one path schema which may represent
122-
# toMany and toOne relationships.
118+
# ResourceIdentifierObject returned by get_component_name()) which serializes type
119+
# and id. These can be lists or individual items depending on whether the
120+
# relationship is toMany or toOne so offer both options since we are not iterating
121+
# over all the possible {related_field}'s but rather rendering one path schema
122+
# which may represent toMany and toOne relationships.
123123
"ResourceIdentifierObject": {
124124
"oneOf": [
125125
{"$ref": "#/components/schemas/relationshipToOne"},
@@ -181,10 +181,12 @@ class SchemaGenerator(drf_openapi.SchemaGenerator):
181181
"properties": {
182182
"pointer": {
183183
"type": "string",
184-
"description": "A [JSON Pointer](https://tools.ietf.org/html/rfc6901) "
185-
"to the associated entity in the request document "
186-
"[e.g. `/data` for a primary data object, or "
187-
"`/data/attributes/title` for a specific attribute.",
184+
"description": (
185+
"A [JSON Pointer](https://tools.ietf.org/html/rfc6901) "
186+
"to the associated entity in the request document "
187+
"[e.g. `/data` for a primary data object, or "
188+
"`/data/attributes/title` for a specific attribute.",
189+
),
188190
},
189191
"parameter": {
190192
"type": "string",
@@ -273,7 +275,8 @@ def get_schema(self, request=None, public=False):
273275
_, view_endpoints = self._get_paths_and_endpoints(None if public else request)
274276

275277
#: `expanded_endpoints` is like view_endpoints with one extra field tacked on:
276-
#: - 'action' copy of current view.action (list/fetch) as this gets reset for each request.
278+
#: - 'action' copy of current view.action (list/fetch) as this gets reset for
279+
# each request.
277280
expanded_endpoints = []
278281
for path, method, view in view_endpoints:
279282
if hasattr(view, "action") and view.action == "retrieve_related":
@@ -371,14 +374,15 @@ def _expand_related(self, path, method, view, view_endpoints):
371374

372375
def _find_related_view(self, view_endpoints, related_serializer, parent_view):
373376
"""
374-
For a given related_serializer, try to find it's "parent" view instance in view_endpoints.
377+
For a given related_serializer, try to find it's "parent" view instance.
378+
375379
:param view_endpoints: list of all view endpoints
376380
:param related_serializer: the related serializer for a given related field
377381
:param parent_view: the parent view (used to find toMany vs. toOne).
378382
TODO: not actually used.
379383
:return:view
380384
"""
381-
for path, method, view in view_endpoints:
385+
for _path, _method, view in view_endpoints:
382386
view_serializer = view.get_serializer()
383387
if isinstance(view_serializer, related_serializer):
384388
return view
@@ -468,7 +472,7 @@ def _get_fields_parameters(self, path, method):
468472
# TODO: See if able to identify the specific types for fields[type]=... and return this:
469473
# name: fields
470474
# in: query
471-
# description: '[sparse fieldsets](https://jsonapi.org/format/#fetching-sparse-fieldsets)'
475+
# description: '[sparse fieldsets](https://jsonapi.org/format/#fetching-sparse-fieldsets)' # noqa: B950
472476
# required: true
473477
# style: deepObject
474478
# schema:
@@ -609,10 +613,11 @@ def get_request_body(self, path, method):
609613
# DRF uses a $ref to the component schema definition, but this
610614
# doesn't work for JSON:API due to the different required fields based on
611615
# the method, so make those changes and inline another copy of the schema.
616+
612617
# TODO: A future improvement could make this DRYer with multiple component schemas:
613-
# A base schema for each viewset that has no required fields
614-
# One subclassed from the base that requires some fields (`type` but not `id` for POST)
615-
# Another subclassed from base with required type/id but no required attributes (PATCH)
618+
# A base schema for each viewset that has no required fields
619+
# One subclassed from the base that requires some fields (`type` but not `id` for POST)
620+
# Another subclassed from base with required type/id but no required attributes (PATCH)
616621

617622
if is_relationship:
618623
item_schema = {"$ref": "#/components/schemas/ResourceIdentifierObject"}
@@ -653,7 +658,9 @@ def get_request_body(self, path, method):
653658
def map_serializer(self, serializer):
654659
"""
655660
Custom map_serializer that serializes the schema using the JSON:API spec.
656-
Non-attributes like related and identity fields, are move to 'relationships' and 'links'.
661+
662+
Non-attributes like related and identity fields, are moved to 'relationships'
663+
and 'links'.
657664
"""
658665
# TODO: remove attributes, etc. for relationshipView??
659666
required = []
@@ -830,7 +837,7 @@ def _add_delete_responses(self, operation):
830837
}
831838
self._add_async_response(operation)
832839
operation["responses"]["204"] = {
833-
"description": "[no content](https://jsonapi.org/format/#crud-deleting-responses-204)",
840+
"description": "[no content](https://jsonapi.org/format/#crud-deleting-responses-204)", # noqa: B950
834841
}
835842
# the 4xx errors:
836843
self._add_generic_failure_responses(operation)

0 commit comments

Comments
 (0)