Skip to content

Introduce flake8 bugbear plugin #1101

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 2 commits into from
Nov 8, 2022
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
2 changes: 1 addition & 1 deletion example/settings/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
REST_FRAMEWORK = {
"PAGE_SIZE": 5,
"EXCEPTION_HANDLER": "rest_framework_json_api.exceptions.exception_handler",
"DEFAULT_PAGINATION_CLASS": "rest_framework_json_api.pagination.JsonApiPageNumberPagination",
"DEFAULT_PAGINATION_CLASS": "rest_framework_json_api.pagination.JsonApiPageNumberPagination", # noqa: B950
"DEFAULT_PARSER_CLASSES": (
"rest_framework_json_api.parsers.JSONParser",
"rest_framework.parsers.FormParser",
Expand Down
12 changes: 6 additions & 6 deletions example/tests/integration/test_non_paginated_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"blogHyperlinked": {
"links": {
"related": "http://testserver/entries/1/blog",
"self": "http://testserver/entries/1/relationships/blog_hyperlinked",
"self": "http://testserver/entries/1/relationships/blog_hyperlinked", # noqa: B950
}
},
"authors": {
Expand All @@ -43,7 +43,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"commentsHyperlinked": {
"links": {
"related": "http://testserver/entries/1/comments",
"self": "http://testserver/entries/1/relationships/comments_hyperlinked",
"self": "http://testserver/entries/1/relationships/comments_hyperlinked", # noqa: B950
}
},
"suggested": {
Expand All @@ -63,7 +63,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"featuredHyperlinked": {
"links": {
"related": "http://testserver/entries/1/featured",
"self": "http://testserver/entries/1/relationships/featured_hyperlinked",
"self": "http://testserver/entries/1/relationships/featured_hyperlinked", # noqa: B950
}
},
"tags": {"data": [], "meta": {"count": 0}},
Expand All @@ -84,7 +84,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"blogHyperlinked": {
"links": {
"related": "http://testserver/entries/2/blog",
"self": "http://testserver/entries/2/relationships/blog_hyperlinked",
"self": "http://testserver/entries/2/relationships/blog_hyperlinked", # noqa: B950
}
},
"authors": {
Expand All @@ -98,7 +98,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"commentsHyperlinked": {
"links": {
"related": "http://testserver/entries/2/comments",
"self": "http://testserver/entries/2/relationships/comments_hyperlinked",
"self": "http://testserver/entries/2/relationships/comments_hyperlinked", # noqa: B950
}
},
"suggested": {
Expand All @@ -118,7 +118,7 @@ def test_multiple_entries_no_pagination(multiple_entries, client):
"featuredHyperlinked": {
"links": {
"related": "http://testserver/entries/2/featured",
"self": "http://testserver/entries/2/relationships/featured_hyperlinked",
"self": "http://testserver/entries/2/relationships/featured_hyperlinked", # noqa: B950
}
},
"tags": {"data": [], "meta": {"count": 0}},
Expand Down
6 changes: 3 additions & 3 deletions example/tests/integration/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_pagination_with_single_entry(single_entry, client):
"blogHyperlinked": {
"links": {
"related": "http://testserver/entries/1/blog",
"self": "http://testserver/entries/1/relationships/blog_hyperlinked",
"self": "http://testserver/entries/1/relationships/blog_hyperlinked", # noqa: B950
}
},
"authors": {
Expand All @@ -43,7 +43,7 @@ def test_pagination_with_single_entry(single_entry, client):
"commentsHyperlinked": {
"links": {
"related": "http://testserver/entries/1/comments",
"self": "http://testserver/entries/1/relationships/comments_hyperlinked",
"self": "http://testserver/entries/1/relationships/comments_hyperlinked", # noqa: B950
}
},
"suggested": {
Expand All @@ -63,7 +63,7 @@ def test_pagination_with_single_entry(single_entry, client):
"featuredHyperlinked": {
"links": {
"related": "http://testserver/entries/1/featured",
"self": "http://testserver/entries/1/relationships/featured_hyperlinked",
"self": "http://testserver/entries/1/relationships/featured_hyperlinked", # noqa: B950
}
},
"tags": {
Expand Down
6 changes: 3 additions & 3 deletions example/tests/integration/test_polymorphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_polymorphism_on_detail_relations(single_company, client):
def test_polymorphism_on_included_relations(single_company, client):
response = client.get(
reverse("company-detail", kwargs={"pk": single_company.pk})
+ "?include=current_project,future_projects,current_art_project,current_research_project"
+ "?include=current_project,future_projects,current_art_project,current_research_project" # noqa: B950
)
content = response.json()
assert (
Expand Down Expand Up @@ -169,14 +169,14 @@ def test_invalid_type_on_polymorphic_model(client):
try:
assert (
content["errors"][0]["detail"]
== "The resource object's type (invalidProjects) is not the type that constitute the "
== "The resource object's type (invalidProjects) is not the type that constitute the " # noqa: B950
"collection represented by the endpoint (one of [researchProjects, artProjects])."
)
except AssertionError:
# Available type list order isn't enforced
assert (
content["errors"][0]["detail"]
== "The resource object's type (invalidProjects) is not the type that constitute the "
== "The resource object's type (invalidProjects) is not the type that constitute the " # noqa: B950
"collection represented by the endpoint (one of [artProjects, researchProjects])."
)

Expand Down
10 changes: 5 additions & 5 deletions example/tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,15 +482,15 @@ def test_search_keywords(self):
"blog": {"data": {"type": "blogs", "id": "1"}},
"blogHyperlinked": {
"links": {
"self": "http://testserver/entries/7/relationships/blog_hyperlinked", # noqa: E501
"self": "http://testserver/entries/7/relationships/blog_hyperlinked", # noqa: B950
"related": "http://testserver/entries/7/blog",
}
},
"authors": {"meta": {"count": 0}, "data": []},
"comments": {"meta": {"count": 0}, "data": []},
"commentsHyperlinked": {
"links": {
"self": "http://testserver/entries/7/relationships/comments_hyperlinked", # noqa: E501
"self": "http://testserver/entries/7/relationships/comments_hyperlinked", # noqa: B950
"related": "http://testserver/entries/7/comments",
}
},
Expand All @@ -515,14 +515,14 @@ def test_search_keywords(self):
},
"suggestedHyperlinked": {
"links": {
"self": "http://testserver/entries/7/relationships/suggested_hyperlinked", # noqa: E501
"self": "http://testserver/entries/7/relationships/suggested_hyperlinked", # noqa: B950
"related": "http://testserver/entries/7/suggested/",
}
},
"tags": {"data": [], "meta": {"count": 0}},
"featuredHyperlinked": {
"links": {
"self": "http://testserver/entries/7/relationships/featured_hyperlinked", # noqa: E501
"self": "http://testserver/entries/7/relationships/featured_hyperlinked", # noqa: B950
"related": "http://testserver/entries/7/featured",
}
},
Expand Down Expand Up @@ -550,7 +550,7 @@ def test_search_multiple_keywords(self):
1. For each keyword, search the 4 search_fields for a match and then get the result
set which is the union of all results for the given keyword.
2. Intersect those results sets such that *all* keywords are represented.
See `example/fixtures/blogentry.json` for the test content that the searches are based on.
See `example/fixtures/blogentry.json` for what test content the searches are based on.
The searches test for both direct entries and related blogs across multiple fields.
"""
for searches in (
Expand Down
4 changes: 2 additions & 2 deletions example/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,8 @@ def test_if_returns_error_on_bad_endpoint_name(self):
expected = [
{
"detail": (
"The resource object's type (bad) is not the type that constitute the collection "
"represented by the endpoint (blogs)."
"The resource object's type (bad) is not the type that constitute the "
"collection represented by the endpoint (blogs)."
),
"source": {"pointer": "/data"},
"status": "409",
Expand Down
4 changes: 2 additions & 2 deletions example/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ class NoPagination(JsonApiPageNumberPagination):

class NonPaginatedEntryViewSet(EntryViewSet):
pagination_class = NoPagination
# override the default filter backends in order to test QueryParameterValidationFilter without
# breaking older usage of non-standard query params like `page_size`.
# override the default filter backends in order to test QueryParameterValidationFilter
# without breaking older usage of non-standard query params like `page_size`.
filter_backends = (
QueryParameterValidationFilter,
OrderingFilter,
Expand Down
1 change: 1 addition & 0 deletions requirements/requirements-codestyle.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
black==22.10.0
flake8==5.0.4
flake8-bugbear==22.10.27
flake8-isort==5.0.0
isort==5.10.1
4 changes: 3 additions & 1 deletion rest_framework_json_api/django_filters/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ class DjangoFilterBackend(DjangoFilterBackend):
- A related resource path
can be used:

``?filter[inventory.item.partNum]=123456`` (where `inventory.item` is the relationship path)
``?filter[inventory.item.partNum]=123456``

where `inventory.item` is the relationship path.

If you are also using rest_framework.filters.SearchFilter you'll want to customize
the name of the query parameter for searching to make sure it doesn't conflict
Expand Down
5 changes: 3 additions & 2 deletions rest_framework_json_api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ def rendered_with_json_api(view):
def exception_handler(exc, context):
# Import this here to avoid potential edge-case circular imports, which
# crashes with:
# "ImportError: Could not import 'rest_framework_json_api.parsers.JSONParser' for API setting
# 'DEFAULT_PARSER_CLASSES'. ImportError: cannot import name 'exceptions'.'"
# "ImportError: Could not import 'rest_framework_json_api.parsers.JSONParser' for
# API setting 'DEFAULT_PARSER_CLASSES'.
# ImportError: cannot import name 'exceptions'.'"
#
# Also see: https://github.com/django-json-api/django-rest-framework-json-api/issues/158
from rest_framework.views import exception_handler as drf_exception_handler
Expand Down
2 changes: 1 addition & 1 deletion rest_framework_json_api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def get_field_info(self, field):
field_info["type"] = self.type_lookup[field]

try:
serializer_model = getattr(serializer.Meta, "model")
serializer_model = serializer.Meta.model
field_info["relationship_type"] = self.relation_type_lookup[
getattr(serializer_model, field.field_name)
]
Expand Down
4 changes: 2 additions & 2 deletions rest_framework_json_api/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ def parse_data(self, result, parser_context):
from rest_framework_json_api.views import RelationshipView

if isinstance(view, RelationshipView):
# We skip parsing the object as JSON:API Resource Identifier Object and not a regular
# Resource Object
# We skip parsing the object as JSON:API Resource Identifier Object and not
# a regular Resource Object
if isinstance(data, list):
for resource_identifier_object in data:
if not (
Expand Down
2 changes: 1 addition & 1 deletion rest_framework_json_api/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def get_links(self, obj=None, lookup_field="pk"):
# AuthorViewSet.as_view({'get': 'retrieve_related'}))
# 2. url(r'^authors/(?P<author_pk>[^/.]+)/bio/$',
# AuthorBioViewSet.as_view({'get': 'retrieve'}))
# So, if related_link_url_kwarg == 'pk' it will add 'related_field' parameter to reverse()
# So, if related_link_url_kwarg == 'pk' it adds 'related_field' parameter to reverse()
if self.related_link_url_kwarg == "pk":
related_kwargs = self_kwargs
else:
Expand Down
43 changes: 25 additions & 18 deletions rest_framework_json_api/schemas/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ class SchemaGenerator(drf_openapi.SchemaGenerator):
"uniqueItems": True,
},
# A RelationshipView uses a ResourceIdentifierObjectSerializer (hence the name
# ResourceIdentifierObject returned by get_component_name()) which serializes type and
# id. These can be lists or individual items depending on whether the relationship is
# toMany or toOne so offer both options since we are not iterating over all the
# possible {related_field}'s but rather rendering one path schema which may represent
# toMany and toOne relationships.
# ResourceIdentifierObject returned by get_component_name()) which serializes type
# and id. These can be lists or individual items depending on whether the
# relationship is toMany or toOne so offer both options since we are not iterating
# over all the possible {related_field}'s but rather rendering one path schema
# which may represent toMany and toOne relationships.
"ResourceIdentifierObject": {
"oneOf": [
{"$ref": "#/components/schemas/relationshipToOne"},
Expand Down Expand Up @@ -181,10 +181,12 @@ class SchemaGenerator(drf_openapi.SchemaGenerator):
"properties": {
"pointer": {
"type": "string",
"description": "A [JSON Pointer](https://tools.ietf.org/html/rfc6901) "
"to the associated entity in the request document "
"[e.g. `/data` for a primary data object, or "
"`/data/attributes/title` for a specific attribute.",
"description": (
"A [JSON Pointer](https://tools.ietf.org/html/rfc6901) "
"to the associated entity in the request document "
"[e.g. `/data` for a primary data object, or "
"`/data/attributes/title` for a specific attribute.",
),
},
"parameter": {
"type": "string",
Expand Down Expand Up @@ -273,7 +275,8 @@ def get_schema(self, request=None, public=False):
_, view_endpoints = self._get_paths_and_endpoints(None if public else request)

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

def _find_related_view(self, view_endpoints, related_serializer, parent_view):
"""
For a given related_serializer, try to find it's "parent" view instance in view_endpoints.
For a given related_serializer, try to find it's "parent" view instance.

:param view_endpoints: list of all view endpoints
:param related_serializer: the related serializer for a given related field
:param parent_view: the parent view (used to find toMany vs. toOne).
TODO: not actually used.
:return:view
"""
for path, method, view in view_endpoints:
for _path, _method, view in view_endpoints:
view_serializer = view.get_serializer()
if isinstance(view_serializer, related_serializer):
return view
Expand Down Expand Up @@ -468,7 +472,7 @@ def _get_fields_parameters(self, path, method):
# TODO: See if able to identify the specific types for fields[type]=... and return this:
# name: fields
# in: query
# description: '[sparse fieldsets](https://jsonapi.org/format/#fetching-sparse-fieldsets)'
# description: '[sparse fieldsets](https://jsonapi.org/format/#fetching-sparse-fieldsets)' # noqa: B950
# required: true
# style: deepObject
# schema:
Expand Down Expand Up @@ -609,10 +613,11 @@ def get_request_body(self, path, method):
# DRF uses a $ref to the component schema definition, but this
# doesn't work for JSON:API due to the different required fields based on
# the method, so make those changes and inline another copy of the schema.

# TODO: A future improvement could make this DRYer with multiple component schemas:
# A base schema for each viewset that has no required fields
# One subclassed from the base that requires some fields (`type` but not `id` for POST)
# Another subclassed from base with required type/id but no required attributes (PATCH)
# A base schema for each viewset that has no required fields
# One subclassed from the base that requires some fields (`type` but not `id` for POST)
# Another subclassed from base with required type/id but no required attributes (PATCH)

if is_relationship:
item_schema = {"$ref": "#/components/schemas/ResourceIdentifierObject"}
Expand Down Expand Up @@ -653,7 +658,9 @@ def get_request_body(self, path, method):
def map_serializer(self, serializer):
"""
Custom map_serializer that serializes the schema using the JSON:API spec.
Non-attributes like related and identity fields, are move to 'relationships' and 'links'.

Non-attributes like related and identity fields, are moved to 'relationships'
and 'links'.
"""
# TODO: remove attributes, etc. for relationshipView??
required = []
Expand Down Expand Up @@ -830,7 +837,7 @@ def _add_delete_responses(self, operation):
}
self._add_async_response(operation)
operation["responses"]["204"] = {
"description": "[no content](https://jsonapi.org/format/#crud-deleting-responses-204)",
"description": "[no content](https://jsonapi.org/format/#crud-deleting-responses-204)", # noqa: B950
}
# the 4xx errors:
self._add_generic_failure_responses(operation)
Expand Down
Loading