@@ -147,9 +147,8 @@ def copy_from(cls,
147147 """Creates a copy of this _LazyValue"""
148148 new_obj = cls (valuegetter = obj .valuegetter , id = obj ._id , marks = obj ._marks )
149149 # make sure the copy will not need to retrieve the result if already done
150- if obj .has_cached_value ():
151- new_obj .cached_value_context = obj .cached_value_context
152- new_obj .cached_value = obj .cached_value
150+ new_obj .cached_value_context = obj .cached_value_context
151+ new_obj .cached_value = obj .cached_value
153152 return new_obj
154153
155154 # noinspection PyMissingConstructor
@@ -225,18 +224,44 @@ def get(self, request_or_item):
225224 """
226225 node = get_test_node (request_or_item )
227226
228- if self . cached_value_context is None or self .cached_value_context () is not node :
227+ if not self .has_cached_value ( node = node ) :
229228 # retrieve the value by calling the function
230229 self .cached_value = self .valuegetter ()
231230 # remember the pytest context of the call with a weak reference to avoir gc issues
232231 self .cached_value_context = weakref .ref (node )
233232
234233 return self .cached_value
235234
236- def has_cached_value (self ):
237- """Return True if there is a cached value in self.value, but with no guarantee that it corresponds to the
238- current request"""
239- return self .cached_value_context is not None
235+ def has_cached_value (self , request_or_item = None , node = None , raise_if_no_context = True ):
236+ """Return True if there is a cached value in self.value correnponding to the given request
237+
238+ A degraded query "is there a cached value" (whatever the context) can be performed by not passing any
239+ request, item or node, and switching `raise_if_no_context` to False.
240+
241+ :param request_or_item: the pytest request or item
242+ :param node: the pytest node if it already known.
243+ :param raise_if_no_context: a boolean indicating if an error should be raised if `request_or_item` and `node`
244+ are both None. Default is `True`.
245+ """
246+ if node is None :
247+ # can we get that context information from the request/item ?
248+ if request_or_item is None :
249+ if raise_if_no_context :
250+ raise ValueError ("No request, item or node was provided: I can not tell if there is a "
251+ "cached value for your context. Switch `raise_if_no_context=False` if"
252+ " you wish to get a degraded answer." )
253+ else :
254+ # degraded answer: just tell if the cache was populated at least once
255+ return self .cached_value_context is not None
256+
257+ # get node context information
258+ node = get_test_node (request_or_item )
259+
260+ elif request_or_item is not None :
261+ raise ValueError ("Only one of `request_or_item` and `node` should be provided" )
262+
263+ # True if there is a cached value context that is the same as the context of the request
264+ return self .cached_value_context is not None and self .cached_value_context () is node
240265
241266 def as_lazy_tuple (self , nb_params ):
242267 return LazyTuple (self , nb_params )
@@ -280,7 +305,7 @@ def __repr__(self):
280305 """Override the inherited method to avoid infinite recursion"""
281306 vals_to_display = (
282307 ('item' , self .item ), # item number first for easier debug
283- ('tuple' , self .host .cached_value if self .host .has_cached_value () else self .host ._lazyvalue ), # lazy value tuple or cached tuple
308+ ('tuple' , self .host .cached_value if self .host .has_cached_value (raise_if_no_context = False ) else self .host ._lazyvalue ), # lazy value tuple or cached tuple
284309 )
285310 return "%s(%s)" % (self .__class__ .__name__ , ", " .join ("%s=%r" % (k , v ) for k , v in vals_to_display ))
286311
@@ -348,8 +373,19 @@ def get(self, request_or_item):
348373 """
349374 return self ._lazyvalue .get (request_or_item )
350375
351- def has_cached_value (self ):
352- return self ._lazyvalue .has_cached_value ()
376+ def has_cached_value (self , request_or_item = None , node = None , raise_if_no_context = True ):
377+ """Return True if there is a cached value correnponding to the given request
378+
379+ A degraded query "is there a cached value" (whatever the context) can be performed by not passing any
380+ request, item or node, and switching `raise_if_no_context` to False.
381+
382+ :param request_or_item: the pytest request or item
383+ :param node: the pytest node if it already known.
384+ :param raise_if_no_context: a boolean indicating if an error should be raised if `request_or_item` and `node`
385+ are both None. Default is `True`.
386+ """
387+ return self ._lazyvalue .has_cached_value (request_or_item = request_or_item , node = node ,
388+ raise_if_no_context = raise_if_no_context )
353389
354390 @property
355391 def cached_value (self ):
@@ -361,17 +397,16 @@ def __getitem__(self, item):
361397 a facade (a LazyTupleItem), so that pytest can store this item independently wherever needed, without
362398 yet calling the value getter.
363399 """
364- if self ._lazyvalue .has_cached_value ():
365- # this is never called by pytest, but keep it for debugging
366- return self ._lazyvalue .cached_value [item ]
367- elif item >= self .theoretical_size :
400+ if item >= self .theoretical_size :
368401 raise IndexError (item )
369402 else :
370- # do not retrieve yet: return a facade
403+ # note: do not use the cache here since we do not know the context.
404+ # return a facade than will be able to use the cache of the tuple
371405 return LazyTupleItem (self , item )
372406
373407 def force_getitem (self , item , request ):
374408 """ Call the underlying value getter, then return self[i]. """
409+ # Note: this will use the cache correctly if needed
375410 argvalue = self .get (request )
376411 try :
377412 return argvalue [item ]
0 commit comments