diff options
-rw-r--r-- | docs/reference.rst | 117 |
1 files changed, 93 insertions, 24 deletions
diff --git a/docs/reference.rst b/docs/reference.rst index 03023fc..70ca38a 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -863,6 +863,7 @@ Some objects expect additional method calls or complex processing for proper def For instance, a ``User`` may need to have a related ``Profile``, where the ``Profile`` is built from the ``User`` object. To support this pattern, factory_boy provides the following tools: + - :class:`PostGenerationMethodCall`: allows you to hook a particular attribute to a function call - :class:`PostGeneration`: this class allows calling a given function with the generated object as argument - :func:`post_generation`: decorator performing the same functions as :class:`PostGeneration` - :class:`RelatedFactory`: this builds or creates a given factory *after* building/creating the first Factory. @@ -1047,60 +1048,121 @@ PostGenerationMethodCall .. class:: PostGenerationMethodCall(method_name, extract_prefix=None, *args, **kwargs) -.. OHAI_VIM* + .. OHAI_VIM* + + The :class:`PostGenerationMethodCall` declaration will call a method on + the generated object just after instantiation. This declaration class + provides a friendly means of generating attributes of a factory instance + during initialization. The declaration is created using the following arguments: + + .. attribute:: method_name + + The name of the method to call on the :attr:`~Factory.FACTORY_FOR` object -The :class:`PostGenerationMethodCall` declaration will call a method on the -generated object just after it being called. + .. attribute:: extract_prefix -Its sole argument is the name of the method to call. -Extra arguments and keyword arguments for the target method may also be provided. + If a string, the keyword argument prefix by which the field will get its + overriding arguments. If ``None``, defaults to the name of the attribute. -Once the object has been generated, the method will be called, with arguments -taken from either the :class:`PostGenerationMethodCall` or prefix-based values: + .. deprecated:: 1.3.0 + Will be removed in 2.0.0 -- If a value was extracted from kwargs (i.e an argument for the name the - :class:`PostGenerationMethodCall` was declared under): + .. attribute:: args - - If the declaration mentionned zero or one argument, the value is passed - directly to the method - - If the declaration used two or more arguments, the value is passed as - ``*args`` to the method + The default set of unnamed arguments to pass to the method given in + :attr:`method_name` -- Otherwise, the arguments used when declaring the :class:`PostGenerationMethodCall` - are used + .. attrinbute:: kwargs -- Keywords extracted from the factory arguments are merged into the defaults - present in the :class:`PostGenerationMethodCall` declaration. + The default set of keyword arguments to pass to the method given in + :attr:`method_name` + +Once the factory instance has been generated, the method specified in +:attr:`~PostGenerationMethodCall.method_name` will be called on the generated object +with any arguments specified in the :class:`PostGenerationMethodCall` declaration, by +default. + +For example, to set a default password on a generated User instance +during instantiation, we could make a declaration for a ``password`` +attribute like below: .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = User - password = factory.PostGenerationMethodCall('set_password', password='') + username = 'user' + password = factory.PostGenerationMethodCall('set_password', + 'defaultpassword') + +When we instantiate a user from the ``UserFactory``, the factory +will create a password attribute by calling ``User.set_password('defaultpassword')``. +Thus, by default, our users will have a password set to ``'defaultpassword'``. .. code-block:: pycon - >>> UserFactory() # Calls user.set_password(password='') - >>> UserFactory(password='test') # Calls user.set_password('test') - >>> UserFactory(password__disabled=True) # Calls user.set_password(password='', disabled=True) + >>> u = UserFactory() # Calls user.set_password('defaultpassword') + >>> u.check_password('defaultpassword') + True + +If the :class:`PostGenerationMethodCall` declaration contained no +arguments or one argument, an overriding the value can be passed +directly to the method through a keyword argument matching the attribute name. +For example we can override the default password specified in the declaration +above by simply passing in the desired password as a keyword argument to the +factory during instantiation. + +.. code-block:: pycon + + >>> other_u = UserFactory(password='different') # Calls user.set_password('different') + >>> other_u.check_password('defaultpassword') + False + >>> other_u.check_password('different') + True + +.. note:: For Django models, unless the object method called by + :class:`PostGenerationMethodCall` saves the object back to the + database, we will have to explicitly remember to save the object back + if we performed a ``create()``. + + .. code-block:: pycon + + >>> u = UserFactory.create() # u.password has not been saved back to the database + >>> u.save() # we must remember to do it ourselves -When the :class:`PostGenerationMethodCall` declaration uses two or more arguments, -the extracted value must be iterable: + We can avoid this by subclassing from :class:`DjangoModelFactory`, + instead, e.g., + + .. code-block:: python + + class UserFactory(factory.DjangoModelFactory): + FACTORY_FOR = User + + username = 'user' + password = factory.PostGenerationMethodCall('set_password', + 'defaultpassword') + + +If instead the :class:`PostGenerationMethodCall` declaration uses two or +more positional arguments, the overriding value must be an iterable. For +example, if we declared the ``password`` attribute like the following, .. code-block:: python class UserFactory(factory.Factory): FACTORY_FOR = User + username = 'user' password = factory.PostGenerationMethodCall('set_password', '', 'sha1') +then we must be cautious to pass in an iterable for the ``password`` +keyword argument when creating an instance from the factory: + .. code-block:: pycon >>> UserFactory() # Calls user.set_password('', 'sha1') >>> UserFactory(password=('test', 'md5')) # Calls user.set_password('test', 'md5') - >>> UserFactory(password__disabled=True) # Calls user.set_password('', 'sha1', disabled=True) >>> # Always pass in a good iterable: >>> UserFactory(password=('test',)) # Calls user.set_password('test') @@ -1116,6 +1178,13 @@ the extracted value must be iterable: value to the :class:`PostGenerationMethodCall` declaration (``PostGenerationMethodCall('method', 'x', 'y_that_is_the_default')``) +Keywords extracted from the factory arguments are merged into the +defaults present in the :class:`PostGenerationMethodCall` declaration. + +.. code-block:: pycon + + >>> UserFactory(password__disabled=True) # Calls user.set_password('', 'sha1', disabled=True) + Module-level functions ---------------------- |