44import inspect
55
66import factory
7+ import factory .builder
8+ import factory .declarations
9+ import factory .enums
710import inflection
811import pytest
912
@@ -59,38 +62,15 @@ def register(factory_class, _name=None, **kwargs):
5962
6063 deps = get_deps (factory_class , model_name = model_name )
6164 related = []
62- for attr , value in factory_class .declarations (factory_class ._meta .postgen_declarations ).items ():
63- value = kwargs .get (attr , value ) # Partial specialization
64- attr_name = SEPARATOR .join ((model_name , attr ))
65-
66- if isinstance (value , (factory .SubFactory , factory .RelatedFactory )):
67- subfactory_class = value .get_factory ()
68- subfactory_deps = get_deps (subfactory_class , factory_class )
6965
70- args = list (subfactory_deps )
71- if isinstance (value , factory .RelatedFactory ):
72- related_model = get_model_name (subfactory_class )
73- args .append (related_model )
74- related .append (related_model )
75- related .append (attr_name )
76- related .extend (subfactory_deps )
77-
78- if isinstance (value , factory .SubFactory ):
79- args .append (inflection .underscore (subfactory_class ._meta .model .__name__ ))
66+ for attr , value in factory_class ._meta .declarations .items ():
67+ args = None
68+ attr_name = SEPARATOR .join ((model_name , attr ))
8069
81- make_fixture (
82- name = attr_name ,
83- module = module ,
84- func = subfactory_fixture ,
85- args = args ,
86- factory_class = subfactory_class ,
87- )
88- else :
89- args = None
70+ if isinstance (value , factory .declarations .PostGeneration ):
71+ value = kwargs .get (attr , None )
9072 if isinstance (value , LazyFixture ):
9173 args = value .args
92- if isinstance (value , factory .declarations .PostGeneration ):
93- value = None
9474
9575 make_fixture (
9676 name = attr_name ,
@@ -99,6 +79,43 @@ def register(factory_class, _name=None, **kwargs):
9979 value = value ,
10080 args = args ,
10181 )
82+ else :
83+ value = kwargs .get (attr , value )
84+
85+ if isinstance (value , (factory .SubFactory , factory .RelatedFactory )):
86+ subfactory_class = value .get_factory ()
87+ subfactory_deps = get_deps (subfactory_class , factory_class )
88+
89+ args = list (subfactory_deps )
90+ if isinstance (value , factory .RelatedFactory ):
91+ related_model = get_model_name (subfactory_class )
92+ args .append (related_model )
93+ related .append (related_model )
94+ related .append (attr_name )
95+ related .extend (subfactory_deps )
96+
97+ if isinstance (value , factory .SubFactory ):
98+ args .append (inflection .underscore (subfactory_class ._meta .model .__name__ ))
99+
100+ make_fixture (
101+ name = attr_name ,
102+ module = module ,
103+ func = subfactory_fixture ,
104+ args = args ,
105+ factory_class = subfactory_class ,
106+ )
107+ else :
108+ if isinstance (value , LazyFixture ):
109+ args = value .args
110+
111+ make_fixture (
112+ name = attr_name ,
113+ module = module ,
114+ func = attr_fixture ,
115+ value = value ,
116+ args = args ,
117+ )
118+
102119 if not hasattr (module , factory_name ):
103120 make_fixture (
104121 name = factory_name ,
@@ -151,7 +168,7 @@ def is_dep(value):
151168
152169 return [
153170 SEPARATOR .join ((model_name , attr ))
154- for attr , value in factory_class .declarations ( factory_class . _meta .postgen_declarations ) .items ()
171+ for attr , value in factory_class ._meta .declarations .items ()
155172 if is_dep (value )
156173 ]
157174
@@ -163,56 +180,71 @@ def evaluate(request, value):
163180
164181def model_fixture (request , factory_name ):
165182 """Model fixture implementation."""
166- factoryboy_request = request .getfuncargvalue ("factoryboy_request" )
183+ factoryboy_request = request .getfixturevalue ("factoryboy_request" )
167184
168185 # Try to evaluate as much post-generation dependencies as possible
169186 factoryboy_request .evaluate (request )
170187
171- factory_class = request .getfuncargvalue (factory_name )
188+ factory_class = request .getfixturevalue (factory_name )
172189 prefix = "" .join ((request .fixturename , SEPARATOR ))
173- data = {}
174- for argname in request ._fixturedef .argnames :
175- if argname .startswith (prefix ) and argname [len (prefix ):] not in factory_class ._meta .postgen_declarations :
176- data [argname [len (prefix ):]] = evaluate (request , request .getfuncargvalue (argname ))
190+
191+ # Create model fixture instance
177192
178193 class Factory (factory_class ):
194+ pass
179195
180- @classmethod
181- def attributes (cls , * args , ** kwargs ):
182- return dict (
183- (key , value )
184- for key , value in super (Factory , cls ).attributes (* args , ** kwargs ).items ()
185- if key in data
186- )
196+ Factory ._meta .base_declarations = dict (
197+ (k , v ) for k , v in Factory ._meta .base_declarations .items ()
198+ if not isinstance (v , factory .declarations .PostGenerationDeclaration )
199+ )
200+ Factory ._meta .post_declarations = factory .builder .DeclarationSet ()
187201
188- Factory ._meta .postgen_declarations = {}
189- Factory ._meta .exclude = [value for value in Factory ._meta .exclude if value in data ]
202+ kwargs = {}
203+ for key in factory_class ._meta .pre_declarations :
204+ argname = "" .join ((prefix , key ))
205+ if argname in request ._fixturedef .argnames :
206+ kwargs [key ] = evaluate (request , request .getfixturevalue (argname ))
190207
191- # Extract post-generation context
192- post_decls = []
193- if factory_class ._meta .postgen_declarations :
194- for attr , decl in sorted (factory_class ._meta .postgen_declarations .items ()):
195- post_decls .append ((attr , decl , decl .extract (attr , data )))
208+ strategy = factory .enums .CREATE_STRATEGY
209+ builder = factory .builder .StepBuilder (Factory ._meta , kwargs , strategy )
210+ step = factory .builder .BuildStep (builder = builder , sequence = Factory ._meta .next_sequence ())
196211
197- # Create model fixture instance
198- instance = Factory (** data )
199- request ._fixturedef .cached_result = (instance , None , None )
200- if hasattr (request , '_fixture_defs' ):
201- request ._fixture_defs [request .fixturename ] = request ._fixturedef
202- else :
203- request ._fixturedefs [request .fixturename ] = request ._fixturedef
212+ instance = Factory (** kwargs )
213+
214+ # Cache the instance value on pytest level so that the fixture can be resolved before the return
215+ request ._fixturedef .cached_result = (instance , 0 , None )
216+ request ._fixture_defs [request .fixturename ] = request ._fixturedef
204217
205218 # Defer post-generation declarations
206- related = []
207- postgen = []
208- for attr , decl , context in post_decls :
219+ deferred = []
220+
221+ for attr in factory_class ._meta .post_declarations .sorted ():
222+
223+ decl = factory_class ._meta .post_declarations .declarations [attr ]
224+
209225 if isinstance (decl , factory .RelatedFactory ):
210- related .append (make_deferred_related (factory_class , request .fixturename , attr ))
226+ deferred .append (make_deferred_related (factory_class , request .fixturename , attr ))
211227 else :
212- postgen .append (
213- make_deferred_postgen (factory_class , request .fixturename , instance , attr , decl , context )
228+ argname = "" .join ((prefix , attr ))
229+ extra = {}
230+ for k , v in factory_class ._meta .post_declarations .contexts [attr ].items ():
231+ if k == '' :
232+ continue
233+ post_attr = SEPARATOR .join ((argname , k ))
234+
235+ if post_attr in request ._fixturedef .argnames :
236+ extra [k ] = evaluate (request , request .getfixturevalue (post_attr ))
237+ else :
238+ extra [k ] = v
239+
240+ postgen_context = factory .builder .PostGenerationContext (
241+ value_provided = True ,
242+ value = evaluate (request , request .getfixturevalue (argname )),
243+ extra = extra ,
244+ )
245+ deferred .append (
246+ make_deferred_postgen (step , factory_class , request .fixturename , instance , attr , decl , postgen_context )
214247 )
215- deferred = related + postgen
216248 factoryboy_request .defer (deferred )
217249
218250 # Try to evaluate as much post-generation dependencies as possible
@@ -232,35 +264,34 @@ def make_deferred_related(factory, fixture, attr):
232264 name = SEPARATOR .join ((fixture , attr ))
233265
234266 def deferred (request ):
235- request .getfuncargvalue (name )
236- # return request.getfuncargvalue(name)
267+ request .getfixturevalue (name )
268+
237269 deferred .__name__ = name
238270 deferred ._factory = factory
239271 deferred ._fixture = fixture
240272 deferred ._is_related = True
241273 return deferred
242274
243275
244- def make_deferred_postgen (factory , fixture , instance , attr , declaration , context ):
276+ def make_deferred_postgen (step , factory_class , fixture , instance , attr , declaration , context ):
245277 """Make deferred function for the post-generation declaration.
246278
247- :param factory: Factory class.
279+ :param step: factory_boy builder step.
280+ :param factory_class: Factory class.
248281 :param fixture: Object fixture name e.g. "author".
249282 :param instance: Parent object instance.
250283 :param attr: Declaration attribute name e.g. "register_user".
251- :param context: Post-generation declaration extraction context.
284+ :param context: Post-generation declaration context.
252285
253286 :note: Deferred function name results in "author__register_user".
254287 """
255288 name = SEPARATOR .join ((fixture , attr ))
256289
257290 def deferred (request ):
258- context .value = evaluate (request , request .getfuncargvalue (name ))
259- context .extra = dict ((key , evaluate (request , value )) for key , value in context .extra .items ())
260- declaration .call (instance , True , context )
261- # return context.value
291+ declaration .call (instance , step , context )
292+
262293 deferred .__name__ = name
263- deferred ._factory = factory
294+ deferred ._factory = factory_class
264295 deferred ._fixture = fixture
265296 deferred ._is_related = False
266297 return deferred
@@ -279,7 +310,7 @@ def attr_fixture(request, value):
279310def subfactory_fixture (request , factory_class ):
280311 """SubFactory/RelatedFactory fixture implementation."""
281312 fixture = inflection .underscore (factory_class ._meta .model .__name__ )
282- return request .getfuncargvalue (fixture )
313+ return request .getfixturevalue (fixture )
283314
284315
285316def get_caller_module (depth = 2 ):
@@ -293,7 +324,6 @@ def get_caller_module(depth=2):
293324
294325
295326class LazyFixture (object ):
296-
297327 """Lazy fixture."""
298328
299329 def __init__ (self , fixture ):
@@ -314,7 +344,7 @@ def evaluate(self, request):
314344 :return: evaluated fixture.
315345 """
316346 if callable (self .fixture ):
317- kwargs = dict ((arg , request .getfuncargvalue (arg )) for arg in self .args )
347+ kwargs = dict ((arg , request .getfixturevalue (arg )) for arg in self .args )
318348 return self .fixture (** kwargs )
319349 else :
320- return request .getfuncargvalue (self .fixture )
350+ return request .getfixturevalue (self .fixture )
0 commit comments