diff --git a/CHANGELOG.md b/CHANGELOG.md index cc46495..0597a77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Fixed + +- service: `update_entity` accepts `200 OK` as well as `204 No Content`, so updates against services such as SAP SuccessFactors no longer raise `HttpError` (#136) - Sena Köse + ## [1.12.1] ### Fixed diff --git a/pyodata/v2/service.py b/pyodata/v2/service.py index 10b5d7a..05449d4 100644 --- a/pyodata/v2/service.py +++ b/pyodata/v2/service.py @@ -23,6 +23,7 @@ HTTP_CODE_OK = 200 HTTP_CODE_CREATED = 201 +HTTP_CODE_NO_CONTENT = 204 def urljoin(*path): @@ -1594,7 +1595,9 @@ def update_entity(self, key=None, method=None, encode_path=True, **kwargs): def update_entity_handler(response): """Gets modified entity encoded in HTTP Response""" - if response.status_code != 204: + # OData V2 answers a successful update with 204 No Content, but some services + # (e.g. SAP SuccessFactors) reply 200 OK instead. + if response.status_code not in (HTTP_CODE_OK, HTTP_CODE_NO_CONTENT): raise HttpError('HTTP modify request for Entity Set {} failed with status code {}' .format(self._name, response.status_code), response) diff --git a/tests/test_service_v2.py b/tests/test_service_v2.py index 24793bf..276c9d9 100644 --- a/tests/test_service_v2.py +++ b/tests/test_service_v2.py @@ -756,6 +756,36 @@ def test_update_entity(service): request.execute() +@responses.activate +@pytest.mark.parametrize('status', [200, 204]) +def test_update_entity_accepts_ok_and_no_content(service, status): + """Update succeeds whether the service answers 204 No Content or 200 OK (e.g. SuccessFactors, #136)""" + + # pylint: disable=redefined-outer-name + responses.add(responses.PATCH, f"{service.url}/{quote('Employees(23)')}", status=status) + + request = service.entity_sets.Employees.update_entity(23) + request.set(NameFirst='Jane') + + assert request.execute() is None + + +@responses.activate +def test_update_entity_rejects_unexpected_status(service): + """Update still raises HttpError for a status that does not mean success""" + + # pylint: disable=redefined-outer-name + responses.add(responses.PATCH, f"{service.url}/{quote('Employees(23)')}", status=400) + + request = service.entity_sets.Employees.update_entity(23) + request.set(NameFirst='Jane') + + with pytest.raises(HttpError) as e_info: + request.execute() + + assert str(e_info.value) == 'HTTP modify request for Entity Set Employees failed with status code 400' + + @responses.activate def test_delete_entity(service): """Check deleting of entity"""