From a3c425925f3ca25d36e7a8c7700d959a06a42aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Mon, 27 Jan 2020 19:10:34 +0100 Subject: [PATCH] v2.2.17 - added coding.sequences.choose (#38) * v2.2.17 - added coding.sequences.choose * link to GitHub at primary page of docs * tests for python 3.5 + code reformat * moved requirements to requirements.txt instead of .travis.yml --- .travis.yml | 1 - CHANGELOG.md | 2 +- docs/coding/sequences.rst | 6 ++++++ docs/index.rst | 5 +++++ requirements.txt | 2 ++ satella/__init__.py | 2 +- satella/coding/sequences/__init__.py | 4 ++++ satella/coding/sequences/choose.py | 30 ++++++++++++++++++++++++++++ tests/test_coding/test_sequences.py | 14 +++++++++++++ 9 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 docs/coding/sequences.rst create mode 100644 satella/coding/sequences/__init__.py create mode 100644 satella/coding/sequences/choose.py create mode 100644 tests/test_coding/test_sequences.py diff --git a/.travis.yml b/.travis.yml index 64cf253c..0835bafe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ python: cache: pip install: - pip install -r requirements.txt - - pip install pyyaml toml - pip install --force-reinstall "coverage>=4.0,<4.4" codeclimate-test-reporter # for codeclimate-test-reporter script: - bash tests/test_posix/test_hang_until_sig.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index ff642575..49fd0d32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # v2.2.17 -* _TBA_ +* added [choose](satella/coding/sequences/choose.py) # v2.2.16 diff --git a/docs/coding/sequences.rst b/docs/coding/sequences.rst new file mode 100644 index 00000000..b08ecbf6 --- /dev/null +++ b/docs/coding/sequences.rst @@ -0,0 +1,6 @@ +choose +====== + +To return the single element that returns true on given callable, use the following function: + +.. autofunction:: satella.coding.sequences.choose diff --git a/docs/index.rst b/docs/index.rst index 3168e26a..222e5ca4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,6 +2,10 @@ Welcome to satella's documentation! =================================== +Visit the project's page at GitHub_! + +.. _GitHub: https://github.com/piotrmaslanka/satella + .. toctree:: :maxdepth: 2 :caption: Contents @@ -11,6 +15,7 @@ Welcome to satella's documentation! coding/functions coding/structures coding/concurrent + coding/sequences instrumentation/traceback instrumentation/metrics exception_handling diff --git a/requirements.txt b/requirements.txt index a4d92cc0..d36e77a2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ psutil +pyyaml +toml diff --git a/satella/__init__.py b/satella/__init__.py index 2b8a694a..342df280 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1,2 +1,2 @@ # coding=UTF-8 -__version__ = '2.2.17a1' +__version__ = '2.2.17' diff --git a/satella/coding/sequences/__init__.py b/satella/coding/sequences/__init__.py new file mode 100644 index 00000000..7dfca4cc --- /dev/null +++ b/satella/coding/sequences/__init__.py @@ -0,0 +1,4 @@ +from .choose import choose + + +__all__ = ['choose'] diff --git a/satella/coding/sequences/choose.py b/satella/coding/sequences/choose.py new file mode 100644 index 00000000..f323506c --- /dev/null +++ b/satella/coding/sequences/choose.py @@ -0,0 +1,30 @@ +import typing as tp + +T = tp.TypeVar('T') + +__all__ = ['choose'] + + +def choose(filter_fun: tp.Callable[[T], bool], iterable: tp.Iterable[T]) -> T: + """ + Return a single value that exists in given iterable + + :param filter_fun: function that returns bool on the single value + :param iterable: iterable to examine + :return: single element in the iterable that matches given input + :raises ValueError: on multiple elements matching, or none at all + """ + elem_candidate = None + found = False + for elem in iterable: + if filter_fun(elem): + if found: + raise ValueError( + 'Multiple values (%s, %s) seen' % (repr(elem_candidate), repr(elem))) + elem_candidate = elem + found = True + + if not found: + raise ValueError('No elements matching given filter seen') + + return elem_candidate diff --git a/tests/test_coding/test_sequences.py b/tests/test_coding/test_sequences.py new file mode 100644 index 00000000..307b756b --- /dev/null +++ b/tests/test_coding/test_sequences.py @@ -0,0 +1,14 @@ +import logging +import typing as tp +import unittest + +from satella.coding.sequences import choose + +logger = logging.getLogger(__name__) + + +class TestSequences(unittest.TestCase): + def test_choose(self): + self.assertEqual(choose(lambda x: x == 2, [1, 2, 3, 4, 5]), 2) + self.assertRaises(ValueError, lambda: choose(lambda x: x % 2 == 0, [1, 2, 3, 4, 5])) + self.assertRaises(ValueError, lambda: choose(lambda x: x == 0, [1, 2, 3, 4, 5])) -- GitLab