From a7274b3f8d0e4f4018b254223d4dfb471fbbbe9d Mon Sep 17 00:00:00 2001 From: Jair Henrique Date: Mon, 11 Oct 2021 16:42:29 -0300 Subject: [PATCH] Improve seq helper --- CHANGELOG.md | 2 ++ model_bakery/utils.py | 38 ++++++++++++++++++++++++++------------ tests/test_utils.py | 35 +++++++++++++++++++++++++---------- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0b437e0..2ac785c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added ### Changed +- Validate `increment_by` parameter of `seq` helper when `value` is an instance of `datetime` [PR #247](https://github.com/model-bakers/model_bakery/pull/247) +- [dev] Fix some `seq` tests. ### Removed diff --git a/model_bakery/utils.py b/model_bakery/utils.py index b44f108d..42617ecb 100644 --- a/model_bakery/utils.py +++ b/model_bakery/utils.py @@ -10,6 +10,8 @@ from .timezone import tz_aware +__all__ = ["import_from_str", "get_calling_module", "seq"] + def import_from_str(import_string: Optional[Union[Callable, str]]) -> Any: """Import an object defined as import if it is an string. @@ -69,11 +71,9 @@ def seq(value, increment_by=1, start=None, suffix=None): Returns: object: generated values for sequential data """ - if type(value) in [datetime.datetime, datetime.date, datetime.time]: - if start: - msg = "start parameter is ignored when using seq with date, time or datetime objects" - warnings.warn(msg) + _validate_sequence_parameters(value, increment_by, start, suffix) + if type(value) in [datetime.datetime, datetime.date, datetime.time]: if type(value) is datetime.date: date = datetime.datetime.combine(value, datetime.datetime.now().time()) elif type(value) is datetime.time: @@ -93,15 +93,29 @@ def seq(value, increment_by=1, start=None, suffix=None): else: yield series_date else: - if suffix and not isinstance(suffix, str): - raise TypeError("Sequences suffix can only be a string") - for n in itertools.count(start or increment_by, increment_by): - if suffix and not isinstance(value, str): - raise TypeError( - "Sequences with suffix can only be used with text values" - ) - elif suffix: + if suffix: yield value + str(n) + suffix else: yield value + type(value)(n) + + +def _validate_sequence_parameters(value, increment_by, start, suffix) -> None: + if suffix: + if not isinstance(suffix, str): + raise TypeError("Sequences suffix can only be a string") + + if not isinstance(value, str): + raise TypeError("Sequences with suffix can only be used with text values") + + if type(value) in [datetime.datetime, datetime.date, datetime.time]: + if not isinstance(increment_by, datetime.timedelta): + raise TypeError( + "Sequences with values datetime.datetime, datetime.date and datetime.time, " + "incremente_by must be a datetime.timedelta." + ) + + if start: + warnings.warn( + "start parameter is ignored when using seq with date, time or datetime objects" + ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 29ac6c2e..152f8e2b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -76,11 +76,10 @@ def test_string_suffix_and_start(self): assert next(sequence) == "cookie113@example.com" def test_string_invalid_suffix(self): - sequence = seq("cookie", suffix=42) - with pytest.raises(TypeError) as exc: - next(sequence) - assert str(exc.value) == "Sequences suffix can only be a string" + next(seq("cookie", suffix=42)) + + assert str(exc.value) == "Sequences suffix can only be a string" def test_int(self): sequence = seq(1) @@ -119,13 +118,12 @@ def test_float_increment_by(self): assert next(sequence) == pytest.approx(6.63) def test_numbers_with_suffix(self): - sequence = seq(1, suffix="iamnotanumber") with pytest.raises(TypeError) as exc: - next(sequence) - assert ( - str(exc.value) - == "Sequences with suffix can only be used with text values" - ) + next(seq(1, suffix="iamnotanumber")) + + assert ( + str(exc.value) == "Sequences with suffix can only be used with text values" + ) def test_date(self): sequence = seq( @@ -162,3 +160,20 @@ def test_datetime(self, settings, use_tz): assert next(sequence) == datetime.datetime( 2021, 2, 12, 00, 39, 58, 457698 ).replace(tzinfo=tzinfo) + + @pytest.mark.parametrize( + "value", + [ + datetime.datetime(2021, 2, 11, 15, 39, 58, 457698), + datetime.date(2021, 2, 11), + datetime.time(15, 39, 58, 457698), + ], + ) + def test_should_raise_exception_for_datetime_instances(self, value): + with pytest.raises(TypeError) as exc: + next(seq(value)) + + assert str(exc.value) == ( + "Sequences with values datetime.datetime, datetime.date and datetime.time, " + "incremente_by must be a datetime.timedelta." + )