Skip to content

Commit

Permalink
Document and rename get_single_item_from_list signature
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanLorenzo committed Jan 29, 2018
1 parent 823b239 commit 4065246
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 21 deletions.
7 changes: 4 additions & 3 deletions shipitscript/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import scriptworker.client

from shipitscript.exceptions import TaskVerificationError, BadInstanceConfigurationError
from shipitscript.utils import get_single_item_from_list
from shipitscript.utils import get_single_item_from_sequence

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -46,17 +46,18 @@ def condition(instance):
return instance['api_root'].rstrip('/') not in PROTECTED_API_ROOTS
no_item_error_message = "Couldn't find an API root that is not a protected one",

return get_single_item_from_list(
return get_single_item_from_sequence(
configured_instances,
condition=condition,
ErrorClass=BadInstanceConfigurationError,
no_item_error_message=no_item_error_message,
too_many_item_error_message='Too many "{}" instances configured'.format(instance_type, allowed_api_root),
append_sequence_to_error_message=False
)


def _get_scope(task):
return get_single_item_from_list(
return get_single_item_from_sequence(
task['scopes'],
condition=lambda scope: scope in VALID_SCOPES,
ErrorClass=TaskVerificationError,
Expand Down
19 changes: 11 additions & 8 deletions shipitscript/test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import tempfile
import json

from shipitscript.utils import load_json, get_single_item_from_list
from shipitscript.utils import load_json, get_single_item_from_sequence


def test_load_json_from_file():
Expand All @@ -17,12 +17,15 @@ def test_load_json_from_file():
assert load_json(output_file) == json_object


@pytest.mark.parametrize('list_, condition, expected', (
@pytest.mark.parametrize('sequence, condition, expected', (
(['a', 'b', 'c'], lambda item: item == 'b', 'b'),
([{'some_key': 1}, {'some_key': 2}, {'some_key': 3}], lambda item: item['some_key'] == 1, {'some_key': 1}),
(({'some_key': 1}, {'some_key': 2}, {'some_key': 3}), lambda item: item['some_key'] == 1, {'some_key': 1}),
(range(1, 10), lambda item: item == 5, 5),
({'a': 1, 'b': 2, 'c': 3}.keys(), lambda item: item == 'b', 'b'),
({'a': 1, 'b': 2, 'c': 3}.values(), lambda item: item == 2, 2),
))
def test_get_single_item_from_list(list_, condition, expected):
assert get_single_item_from_list(list_, condition) == expected
def test_get_single_item_from_sequence(sequence, condition, expected):
assert get_single_item_from_sequence(sequence, condition) == expected


class SomeCustomError(Exception):
Expand All @@ -39,16 +42,16 @@ class SomeCustomError(Exception):
(['a', 'b', 'c'], lambda _: True, ValueError, None, None, None, False, "Too many items matched condition. Given: ['a', 'b', 'c']"),
)
)
def test_fail_get_single_item_from_list(
def test_fail_get_single_item_from_sequence(
list_, condition, ErrorClass, no_item_error_message, too_many_item_error_message, append_list_to_error_message,
has_all_params, expected_message
):
with pytest.raises(ErrorClass) as exec_info:
if has_all_params:
get_single_item_from_list(
get_single_item_from_sequence(
list_, condition, ErrorClass, no_item_error_message, too_many_item_error_message, append_list_to_error_message
)
else:
get_single_item_from_list(list_, condition)
get_single_item_from_sequence(list_, condition)

assert str(exec_info.value) == expected_message
37 changes: 27 additions & 10 deletions shipitscript/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,37 @@ def load_json(path):
return json.load(fh)


def get_single_item_from_list(
list_, condition, ErrorClass=ValueError, no_item_error_message='No item matched condition',
def get_single_item_from_sequence(
sequence, condition,
ErrorClass=ValueError,
no_item_error_message='No item matched condition',
too_many_item_error_message='Too many items matched condition',
append_list_to_error_message=True
append_sequence_to_error_message=True
):
filtered_list = [item for item in list_ if condition(item)]
number_of_items_in_filtered_list = len(filtered_list)
if number_of_items_in_filtered_list == 0:
"""Returns an item from a python sequence based on the given condition.
Args:
sequence (sequence): The sequence to filter
condition: A function that serves to filter items from `sequence`. Function \
must have one argument (a single item from the sequence) and return a boolean.
ErrorClass (Exception): The error type raised in case the item isn't unique
no_item_error_message (str): The message raised when no item matched the condtion
too_many_item_error_message (str): The message raised when more than one item matched the condition
append_sequence_to_error_message (bool): Show or hide what was the tested sequence in the error message.
Hiding it may prevent sensitive data (such as password) to be exposed to public logs
Returns:
The only item in the sequence which matched the condition
"""
filtered_sequence = [item for item in sequence if condition(item)]
number_of_items_in_filtered_sequence = len(filtered_sequence)
if number_of_items_in_filtered_sequence == 0:
error_message = no_item_error_message
elif number_of_items_in_filtered_list > 1:
elif number_of_items_in_filtered_sequence > 1:
error_message = too_many_item_error_message
else:
return filtered_list[0]
return filtered_sequence[0]

if append_list_to_error_message:
error_message = '{}. Given: {}'.format(error_message, list_)
if append_sequence_to_error_message:
error_message = '{}. Given: {}'.format(error_message, sequence)
raise ErrorClass(error_message)

0 comments on commit 4065246

Please sign in to comment.