Skip to content

Commit

Permalink
Feature/setitem response (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
alanag13 committed May 11, 2020
1 parent f9189a8 commit 22bc834
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ how a consumer would use the library (e.g. adding unit tests, updating documenta

- `RuleId`, `RuleSource` and `RuleType` filter classes to `py42.sdk.queries.alerts.filters.alert_filter` module.

- `Py42Response` items now have `__setitem__` support in order facilitate manipulating a response. For example, `response["users"][0]["username"] = "something else` is now possible.

- `Py42Resonse` items can now be iterated over multiple times.

## 1.1.1 - 2020-05-04

### Fixed
Expand Down
22 changes: 17 additions & 5 deletions src/py42/response.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json

from py42._internal.compat import reprlib, str
from py42.exceptions import Py42Error


class Py42Response(object):
Expand All @@ -16,14 +17,25 @@ def __init__(self, requests_response):
except ValueError:
self._data_root = self._response.text or u""

# looping over a Py42Response will loop through list items, dict keys, or str characters
self._iter = iter(self._data_root)

def __getitem__(self, key):
return self._data_root[key]
try:
return self._data_root[key]
except TypeError as e:
data_root_type = type(self._data_root)
message = u"The Py42Response root is of type {}, but __getitem__ got a key of {}, which is incompatible."
raise Py42Error(message)

def __setitem__(self, key, value):
try:
self._data_root[key] = value
except TypeError as e:
data_root_type = type(self._data_root)
message = u"The Py42Response root is of type {}, but __setitem__ got a key of {} and value of {}, which is incompatible."
raise Py42Error(message)

def __iter__(self):
return self._iter
# looping over a Py42Response will loop through list items, dict keys, or str characters
return iter(self._data_root)

@property
def encoding(self):
Expand Down
54 changes: 53 additions & 1 deletion tests/sdk/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
from requests import Response

from py42.response import Py42Response
from py42.exceptions import Py42Error

JSON_LIST_WITH_DATA_NODE = '{"data": {"item_list_key": [{"foo": "foo_val"}, {"bar": "bar_val"}]}}'
JSON_DICT_WITH_DATA_NODE = '{"data": {"item_list_key": {"foo": "foo_val"}}}'

JSON_LIST_NO_DATA_NODE = '{"item_list_key": [{"foo": "foo_val"}, {"bar": "bar_val"}]}'
JSON_DICT_NO_DATA_NODE = '{"item_list_key": {"foo": "foo_val"}}'
JSON_DICT_NO_DATA_NODE = '{"item_list_key": {"foo": "foo_val", "bar": "bar_val"}}'

PLAIN_TEXT = "TEST_PLAIN_TEXT"

Expand Down Expand Up @@ -62,6 +63,34 @@ def test_getitem_returns_dict_keys_no_data_node(self, mock_response_dict_no_data
response = Py42Response(mock_response_dict_no_data_node)
assert type(response["item_list_key"]) == dict

def test_setitem_modifies_dict_keys_with_data_node_to_expected_value(
self, mock_response_dict_data_node
):
response = Py42Response(mock_response_dict_data_node)
response["item_list_key"]["foo"] = "newfooval"
assert response["item_list_key"]["foo"] == "newfooval"

def test_setitem_modifies_dict_keys_with_no_data_node_to_expected_value(
self, mock_response_dict_no_data_node
):
response = Py42Response(mock_response_dict_no_data_node)
response["item_list_key"]["foo"] = "newfooval"
assert response["item_list_key"]["foo"] == "newfooval"

def test_setitem_modifies_list_items_with_data_node_to_expected_value(
self, mock_response_list_data_node
):
response = Py42Response(mock_response_list_data_node)
response["item_list_key"][0] = "testmodifylistitem"
assert response["item_list_key"][0] == "testmodifylistitem"

def test_setitem_modifies_list_items_with_no_data_node_to_expected_value(
self, mock_response_list_no_data_node
):
response = Py42Response(mock_response_list_no_data_node)
response["item_list_key"][0] = "testmodifylistitem"
assert response["item_list_key"][0] == "testmodifylistitem"

def test_text_json_no_data_node_returns_raw_json(self, mock_response_list_no_data_node):
response = Py42Response(mock_response_list_no_data_node)
assert response.text == JSON_LIST_NO_DATA_NODE
Expand Down Expand Up @@ -100,3 +129,26 @@ def test_iter_content_calls_request_iter_content(self, mock_response_not_json):
mock_response_not_json.iter_content.assert_called_once_with(
chunk_size=128, decode_unicode=True
)

def test_iter_can_be_looped_over_multiple_times(self, mock_response_dict_no_data_node):
response = Py42Response(mock_response_dict_no_data_node)
items = 0
for dictitem in response["item_list_key"]:
items += 1
assert items == 2

items = 0

for dictitem in response["item_list_key"]:
items += 1
assert items == 2

def test_setitem_raises_py42_error_on_invalid_assignment(self, mock_response_not_json):
response = Py42Response(mock_response_not_json)
with pytest.raises(Py42Error):
response[0] = "test"

def test_getitem_raises_py42_error_on_invalid_subscript(self, mock_response_not_json):
response = Py42Response(mock_response_not_json)
with pytest.raises(Py42Error):
response["test"]

0 comments on commit 22bc834

Please sign in to comment.