diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d14d29f..a3011d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ any parts of the framework not mentioned in the documentation should generally b ### Fixed * Adjusted error messages to correctly use capitial "JSON:API" abbreviation as used in the specification. +* Avoid error when `parser_context` is `None` while parsing. ### Changed diff --git a/rest_framework_json_api/parsers.py b/rest_framework_json_api/parsers.py index 434e2925..4c04fd52 100644 --- a/rest_framework_json_api/parsers.py +++ b/rest_framework_json_api/parsers.py @@ -82,7 +82,8 @@ def parse(self, stream, media_type=None, parser_context=None): raise ParseError("Received document does not contain primary data") data = result.get("data") - view = parser_context["view"] + parser_context = parser_context or {} + view = parser_context.get("view") from rest_framework_json_api.views import RelationshipView @@ -107,6 +108,7 @@ def parse(self, stream, media_type=None, parser_context=None): return data request = parser_context.get("request") + method = request and request.method # Sanity check if not isinstance(data, dict): @@ -115,7 +117,7 @@ def parse(self, stream, media_type=None, parser_context=None): ) # Check for inconsistencies - if request.method in ("PUT", "POST", "PATCH"): + if method in ("PUT", "POST", "PATCH"): resource_name = get_resource_name( parser_context, expand_polymorphic_types=True ) @@ -138,12 +140,12 @@ def parse(self, stream, media_type=None, parser_context=None): resource_types=", ".join(resource_name), ) ) - if not data.get("id") and request.method in ("PATCH", "PUT"): + if not data.get("id") and method in ("PATCH", "PUT"): raise ParseError( "The resource identifier object must contain an 'id' member" ) - if request.method in ("PATCH", "PUT"): + if method in ("PATCH", "PUT"): lookup_url_kwarg = getattr(view, "lookup_url_kwarg", None) or getattr( view, "lookup_field", None ) diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 5dd9036e..f1207757 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -15,8 +15,8 @@ def parser(self): return JSONParser() @pytest.fixture - def parse(self, parser, parser_context): - def parse_wrapper(data): + def parse(self, parser): + def parse_wrapper(data, parser_context): stream = BytesIO(json.dumps(data).encode("utf-8")) return parser.parse(stream, None, parser_context) @@ -41,6 +41,7 @@ def test_parse_formats_field_names( settings, format_field_names, parse, + parser_context, ): settings.JSON_API_FORMAT_FIELD_NAMES = format_field_names @@ -59,14 +60,14 @@ def test_parse_formats_field_names( } } - result = parse(data) + result = parse(data, parser_context) assert result == { "id": "123", "test_attribute": "test-value", "test_relationship": {"id": "123", "type": "TestRelationship"}, } - def test_parse_extracts_meta(self, parse): + def test_parse_extracts_meta(self, parse, parser_context): data = { "data": { "type": "BasicModel", @@ -74,10 +75,21 @@ def test_parse_extracts_meta(self, parse): "meta": {"random_key": "random_value"}, } - result = parse(data) + result = parse(data, parser_context) assert result["_meta"] == data["meta"] - def test_parse_preserves_json_value_field_names(self, settings, parse): + def test_parse_with_default_arguments(self, parse): + data = { + "data": { + "type": "BasicModel", + }, + } + result = parse(data, None) + assert result == {} + + def test_parse_preserves_json_value_field_names( + self, settings, parse, parser_context + ): settings.JSON_API_FORMAT_FIELD_NAMES = "dasherize" data = { @@ -87,17 +99,17 @@ def test_parse_preserves_json_value_field_names(self, settings, parse): }, } - result = parse(data) + result = parse(data, parser_context) assert result["json_value"] == {"JsonKey": "JsonValue"} - def test_parse_raises_error_on_empty_data(self, parse): + def test_parse_raises_error_on_empty_data(self, parse, parser_context): data = [] with pytest.raises(ParseError) as excinfo: - parse(data) + parse(data, parser_context) assert "Received document does not contain primary data" == str(excinfo.value) - def test_parse_fails_on_list_of_objects(self, parse): + def test_parse_fails_on_list_of_objects(self, parse, parser_context): data = { "data": [ { @@ -108,7 +120,7 @@ def test_parse_fails_on_list_of_objects(self, parse): } with pytest.raises(ParseError) as excinfo: - parse(data) + parse(data, parser_context) assert ( "Received data is not a valid JSON:API Resource Identifier Object" @@ -124,7 +136,7 @@ def test_parse_fails_when_id_is_missing_on_patch(self, rf, parse, parser_context } with pytest.raises(ParseError) as excinfo: - parse(data) + parse(data, parser_context) assert "The resource identifier object must contain an 'id' member" == str( excinfo.value