rbarrois/factory_boy — pull request #36 by gotgenes (2013-01-18 20:59:02+00:00)
Title: Allow overriding default arguments in PostGenerationMethodCall

This changeset allows overriding default arguments to the object method of a PostGenerationMethodCall instance. Seeing an example of the new capability will help with clarity:

```python
class UserFactory(factory.Factory):
FACTORY_FOR = User

username = 'user'
password = factory.PostGenerationMethodCall(
'set_password', None, 'defaultpassword')
```

Before this changeset:

```python
>>> from factories import UserFactory
>>> u = UserFactory.build(password='different') # does not actually override 'defaultpassword'!!!
>>> u.check_password('different')
False
>>> u.check_password('defaultpassword')
True
```

After this changeset is applied:

```python
>>> from factories import UserFactory
>>> u = UserFactory.build(password='different')
>>> u.check_password('different')
True
>>> u.check_password('defaultpassword')
False
>>> # We are victorious!! \o/
```

This patch also creates a subclass, DjangoPostGenerationMethodCall, that will call the instance’s save() method after making the call to the object method passed in as an argument. For instance in the previous example, we would have to do:

```python
>>> u = UserFactory.create() # u.password has not been saved back to the database
>>> u.save() # we must remember to do it ourselves
```

If instead we use DjangoPostGenerationMethodCall like so

```python
class UserFactory(factory.Factory):
...
password = factory.DjangoPostGenerationMethodCall(
'set_password', None, 'defaultpassword')
```

we just have to do

```python
>>> u = UserFactory.create() # u.password is automatically committed to the database
```

I don't really find this extra class elegant, and it could cause some confusion to users of factory_boy in that nearly all of them should be using DjangoPostGenerationMethodCall instead of PostGenerationMethodCall, but I understand that factory_boy is trying to be more abstract and not a tool only for Django. I went with this solution based on Django

This changeset includes new unit tests in test_declarations.py. These tests depend on the presence of the [Python mock library](http://www.voidspace.org.uk/python/mock/). Although this introduces a third-party dependency in Python 2, it is [part of the Python 3 standard library](http://docs.python.org/3/library/unittest.mock.html). I think it's beneficial to introduce mock into the unit tests, and it certainly made it very easy to test these new changes.

I have also added appropriate documentation in post_generation.rst. I think some hint of PostGenerationMethodCall in the index.rst/README.rst would be helpful but I did not apply any changes there. I feel like this should be presented as the means of setting user passwords rather than the method presented in the README that overrides the _prepare method. This feels more elegant and provides a one-liner solution.