Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for suffix in seq (fix #93) #111

Merged
merged 11 commits into from
Oct 6, 2020
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added
- Support to django 3.1 `JSONField` [PR #85](https://github.com/model-bakers/model_bakery/pull/85) and [PR #106](https://github.com/model-bakers/model_bakery/pull/106)
- [dev] Changelog reminder (GitHub action)
- Added type annotations [PR #100](https://github.com/model-bakers/model_bakery/pull/100)
- Support for Python 3.9 [PR #113](https://github.com/model-bakers/model_bakery/pull/113/)
- [dev] Changelog reminder (GitHub action)

### Changed
- Support for `prefix` in `seq` values ([PR #111](https://github.com/model-bakers/model_bakery/pull/111) fixes [Issue #93](https://github.com/model-bakers/model_bakery/issues/93))
- [dev] CI switched to GitHub Actions
- [dev] Freeze dev requirements
- [dev] Add Django 3.1 to test matrix [PR #103](https://github.com/model-bakers/model_bakery/pull/103) and [PR #112](https://github.com/model-bakers/model_bakery/pull/112)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pip install model_bakery
class Customer(models.Model):
enjoy_jards_macale = models.BooleanField()
name = models.CharField(max_length=30)
email = models.EmailField()
age = models.IntegerField()
bio = models.TextField()
days_since_last_login = models.BigIntegerField()
Expand Down
2 changes: 2 additions & 0 deletions docs/source/basic_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ File: **models.py** ::
"""
enjoy_jards_macale = models.BooleanField()
name = models.CharField(max_length=30)
email = models.EmailField()
age = models.IntegerField()
bio = models.TextField()
days_since_last_login = models.BigIntegerField()
Expand Down Expand Up @@ -68,6 +69,7 @@ File: **models.py** ::
"""
enjoy_jards_macale = models.BooleanField()
name = models.CharField(max_length=30)
email = models.EmailField()
age = models.IntegerField()
bio = models.TextField()
days_since_last_login = models.BigIntegerField()
Expand Down
18 changes: 18 additions & 0 deletions docs/source/recipes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,24 @@ Sometimes, you have a field with an unique value and using ``make`` can cause ra

This will append a counter to strings to avoid uniqueness problems and it will sum the counter with numerical values.

An optional ``suffix`` parameter can be supplied to augment the value for cases like generating emails
or other strings with common suffixes.

.. code-block:: python

>>> from model_bakery import.recipe import Recipe, seq
>>> from shop.models import Customer

>>> customer = Recipe(Customer, email=seq('user', suffix='@example.com'))

>>> customer = baker.make_recipe('shop.customer')
>>> customer.email
'user1@example.com'

>>> customer = baker.make_recipe('shop.customer')
>>> customer.email
'user2@example.com'

Sequences and iterables can be used not only for recipes, but with ``baker`` as well:

.. code-block:: python
Expand Down
35 changes: 33 additions & 2 deletions model_bakery/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,28 @@ def import_from_str(import_string: Optional[Union[Callable, str]]) -> Any:
return import_string


def seq(value, increment_by=1, start=None):
def seq(value, increment_by=1, start=None, suffix=None):
timjklein36 marked this conversation as resolved.
Show resolved Hide resolved
"""Generate a sequence of values based on a running count.

This function can be used to generate sequences of `int`, `float`,
`datetime`, `date`, `time`, or `str`: whatever the `type` is of the
provided `value`.

Args:
value (object): the value at which to begin generation (this will
be ignored for types `datetime`, `date`, and `time`)
increment_by (`int` or `float`, optional): the amount by which to
increment for each generated value (defaults to `1`)
start (`int` or `float`, optional): the value at which the sequence
will begin to add to `value` (if `value` is a `str`, `start` will
be appended to it)
suffix (`str`, optional): for `str` `value` sequences, this will be
appended to the end of each generated value (after the counting
value is appended)

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"
Expand All @@ -46,5 +67,15 @@ def seq(value, increment_by=1, start=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):
yield value + type(value)(n)
if suffix and not isinstance(value, str):
raise TypeError(
"Sequences with suffix can only be used with text values"
)
elif suffix:
yield value + str(n) + suffix
else:
yield value + type(value)(n)
46 changes: 46 additions & 0 deletions tests/test_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,39 @@ def test_increment_for_strings(self):
person = baker.make_recipe("tests.generic.serial_person")
assert person.name == "joe3"

def test_increment_for_strings_with_suffix(self):
timjklein36 marked this conversation as resolved.
Show resolved Hide resolved
from model_bakery.recipe import seq # NoQA

fred_person = person_recipe.extend(email=seq("fred", suffix="@example.com"))
person = fred_person.make()
assert person.email == "fred1@example.com"
person = fred_person.make()
assert person.email == "fred2@example.com"
person = fred_person.make()
assert person.email == "fred3@example.com"

def test_increment_for_strings_with_bad_suffix(self):
from model_bakery.recipe import seq # NoQA

# Bad suffix
bob_person = person_recipe.extend(email=seq("bob", suffix=42))
with pytest.raises(TypeError) as exc:
bob_person.make()
assert str(exc.value) == "Sequences suffix can only be a string"

def test_increment_for_strings_with_suffix_and_start(self):
from model_bakery.recipe import seq # NoQA

fred_person = person_recipe.extend(
email=seq("fred", start=5, suffix="@example.com")
)
person = fred_person.make()
assert person.email == "fred5@example.com"
person = fred_person.make()
assert person.email == "fred6@example.com"
person = fred_person.make()
assert person.email == "fred7@example.com"

def test_increment_for_numbers(self):
dummy = baker.make_recipe("tests.generic.serial_numbers")
assert dummy.default_int_field == 11
Expand Down Expand Up @@ -442,6 +475,19 @@ def test_increment_for_numbers_2(self):
assert dummy.default_decimal_field == Decimal("23.1")
assert dummy.default_float_field == 4.23

def test_increment_for_numbers_with_suffix(self):
from model_bakery.recipe import seq # NoQA

with pytest.raises(TypeError) as exc:
baker.make_recipe(
"tests.generic.serial_numbers",
default_int_field=seq(1, suffix="will not work"),
)
assert (
str(exc.value)
== "Sequences with suffix can only be used with text values"
)

def test_creates_unique_field_recipe_using_for_iterator(self):
for i in range(1, 4):
dummy = baker.make_recipe("tests.generic.dummy_unique_field")
Expand Down