Skip to content

Allow parser context to be None #981

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
Sep 23, 2021
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 6 additions & 4 deletions rest_framework_json_api/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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):
Expand All @@ -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
)
Expand All @@ -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
)
Expand Down
36 changes: 24 additions & 12 deletions tests/test_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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

Expand All @@ -59,25 +60,36 @@ 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",
},
"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 = {
Expand All @@ -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": [
{
Expand All @@ -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"
Expand All @@ -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
Expand Down