Skip to content

Commit 2dda824

Browse files
mamiksikfilak-sap
authored andcommitted
Add delete entity function
We never realized that delete entity function has been missing until issue 54 was created. Hence this commit which adds that functionality to our lib. All added code is tested and 'How to use delete function' was also added to the documentation.
1 parent 00667d9 commit 2dda824

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

docs/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ The User Guide
5050
usage/initialization.rst
5151
usage/querying.rst
5252
usage/creating.rst
53+
usage/deleting.rst
5354
usage/function_imports.rst
5455
usage/metadata.rst
5556
usage/advanced.rst

docs/usage/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ The User Guide
44
* [Initialization](initialization.rst)
55
* [Querying](querying.rst)
66
* [Creating](creating.rst)
7+
* [Deleting](deleting.rst)
78
* [Function Imports](function_imports.rst)
89
* [Metadata](metadata.rst)
910
* [Advanced](advanced.rst)

docs/usage/deleting.rst

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Deleting
2+
========
3+
4+
.. _CSRF: https://en.wikipedia.org/wiki/Cross-site_request_forgery
5+
.. _Requests: https://2.python-requests.org/en/master/
6+
7+
The delete action executes the HTTP method DELETE which is usually protected by
8+
CSRF_ and therefore you must make some effort to initialize your HTTP Session
9+
to send DELETE requests acceptable by the remote server.
10+
11+
Let's assume you use the python library Requests_
12+
13+
.. code-block:: python
14+
15+
import pyodata
16+
import requests
17+
18+
SERVICE_URL = 'http://example.io/TheServiceRoot/'
19+
20+
session = requests.Session()
21+
response = session.head(SERVICE_URL, headers={'x-csrf-token': 'fetch'})
22+
token = response.headers.get('x-csrf-token', '')
23+
session.headers.update({'x-csrf-token': token})
24+
25+
theservice = pyodata.Client(SERVICE_URL, session)
26+
27+
28+
Deleting an entity
29+
------------------
30+
31+
You can either delete entity by passing its PropertyRef value to the delete function
32+
33+
.. code-block:: python
34+
35+
request = service.entity_sets.Employees.delete_entity(23)
36+
request.execute()
37+
38+
or by passing the EntityKey object
39+
40+
.. code-block:: python
41+
42+
key = EntityKey(service.schema.entity_type('Employee'), ID=23)
43+
request = service.entity_sets.Employees.delete_entity(key=key)
44+
request.execute()

pyodata/v2/service.py

+38
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,25 @@ def set(self, **kwargs):
480480
return self
481481

482482

483+
class EntityDeleteRequest(ODataHttpRequest):
484+
"""Used for deleting entity (DELETE operations on a single entity)"""
485+
486+
def __init__(self, url, connection, handler, entity_set, entity_key):
487+
super(EntityDeleteRequest, self).__init__(url, connection, handler)
488+
self._logger = logging.getLogger(LOGGER_NAME)
489+
self._entity_set = entity_set
490+
self._entity_key = entity_key
491+
492+
self._logger.debug('New instance of EntityDeleteRequest for entity type: %s', entity_set.entity_type.name)
493+
494+
def get_path(self):
495+
return self._entity_set.name + self._entity_key.to_key_string()
496+
497+
def get_method(self):
498+
# pylint: disable=no-self-use
499+
return 'DELETE'
500+
501+
483502
class EntityModifyRequest(ODataHttpRequest):
484503
"""Used for modyfing entities (UPDATE/MERGE operations on a single entity)
485504
@@ -1131,6 +1150,25 @@ def update_entity_handler(response):
11311150
return EntityModifyRequest(self._service.url, self._service.connection, update_entity_handler, self._entity_set,
11321151
entity_key)
11331152

1153+
def delete_entity(self, key: EntityKey = None, **kwargs):
1154+
"""Delete the entity"""
1155+
1156+
def delete_entity_handler(response):
1157+
"""Check if entity deletion was successful"""
1158+
1159+
if response.status_code != 204:
1160+
raise HttpError(f'HTTP POST for Entity delete {self._name} '
1161+
f'failed with status code {response.status_code}',
1162+
response)
1163+
1164+
if key is not None and isinstance(key, EntityKey):
1165+
entity_key = key
1166+
else:
1167+
entity_key = EntityKey(self._entity_set.entity_type, key, **kwargs)
1168+
1169+
return EntityDeleteRequest(self._service.url, self._service.connection, delete_entity_handler, self._entity_set,
1170+
entity_key)
1171+
11341172

11351173
# pylint: disable=too-few-public-methods
11361174
class EntityContainer:

tests/test_service_v2.py

+40
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,46 @@ def test_update_entity(service):
590590
request.execute()
591591

592592

593+
@responses.activate
594+
def test_delete_entity(service):
595+
"""Check deleting of entity"""
596+
597+
responses.add(responses.DELETE, f"{service.url}/Employees(23)", status=204)
598+
request = service.entity_sets.Employees.delete_entity(23)
599+
600+
assert isinstance(request, pyodata.v2.service.EntityDeleteRequest)
601+
assert request.execute() is None
602+
603+
604+
@responses.activate
605+
def test_delete_entity_with_key(service):
606+
"""Check deleting of entity with key"""
607+
608+
responses.add(responses.DELETE, f"{service.url}/Employees(ID=23)", status=204)
609+
key = EntityKey(service.schema.entity_type('Employee'), ID=23)
610+
request = service.entity_sets.Employees.delete_entity(key=key)
611+
612+
assert isinstance(request, pyodata.v2.service.EntityDeleteRequest)
613+
assert request.execute() is None
614+
615+
616+
@responses.activate
617+
def test_delete_entity_http_error(service):
618+
"""Check if error is raisen when deleting unknown entity"""
619+
620+
responses.add(responses.DELETE, f"{service.url}/Employees(ID=23)", status=404)
621+
key = EntityKey(service.schema.entity_type('Employee'), ID=23)
622+
request = service.entity_sets.Employees.delete_entity(key=key)
623+
624+
assert isinstance(request, pyodata.v2.service.EntityDeleteRequest)
625+
626+
with pytest.raises(HttpError) as caught_ex:
627+
request.execute()
628+
629+
assert str(caught_ex.value).startswith('HTTP POST for Entity delete')
630+
assert caught_ex.value.response.status_code == 404
631+
632+
593633
def test_update_entity_with_entity_key(service):
594634
"""Make sure the method update_entity handles correctly the parameter key which is EntityKey"""
595635

0 commit comments

Comments
 (0)