2929from _pytest .fixtures import fixture
3030from _pytest .fixtures import FixtureRequest
3131from _pytest .main import Session
32+ from _pytest .nodeid import NodeId
3233from _pytest .nodes import Directory
3334from _pytest .nodes import File
3435from _pytest .reports import TestReport
@@ -286,7 +287,7 @@ def sort_key(node: nodes.Item | nodes.Collector) -> bool:
286287
287288 # Only filter with known failures.
288289 if not self ._collected_at_least_one_failure :
289- if not any (x .nodeid in lastfailed for x in result ):
290+ if not any (x .id in lastfailed for x in result ):
290291 return res
291292 self .lfplugin .config .pluginmanager .register (
292293 LFPluginCollSkipfiles (self .lfplugin ), "lfplugin-collskip"
@@ -297,7 +298,7 @@ def sort_key(node: nodes.Item | nodes.Collector) -> bool:
297298 result [:] = [
298299 x
299300 for x in result
300- if x .nodeid in lastfailed
301+ if x .id in lastfailed
301302 # Include any passed arguments (not trivial to filter).
302303 or session .isinitpath (x .path )
303304 # Keep all sub-collectors.
@@ -319,9 +320,7 @@ def pytest_make_collect_report(
319320 if collector .path not in self .lfplugin ._last_failed_paths :
320321 self .lfplugin ._skipped_files += 1
321322
322- return CollectReport (
323- collector .nodeid , "passed" , longrepr = None , result = []
324- )
323+ return CollectReport (collector .id , "passed" , longrepr = None , result = [])
325324 return None
326325
327326
@@ -333,7 +332,10 @@ def __init__(self, config: Config) -> None:
333332 active_keys = "lf" , "failedfirst"
334333 self .active = any (config .getoption (key ) for key in active_keys )
335334 assert config .cache
336- self .lastfailed : dict [str , bool ] = config .cache .get ("cache/lastfailed" , {})
335+ self .lastfailed : dict [NodeId , bool ] = {
336+ NodeId .parse (k ): v
337+ for k , v in config .cache .get ("cache/lastfailed" , {}).items ()
338+ }
337339 self ._previously_failed_count : int | None = None
338340 self ._report_status : str | None = None
339341 self ._skipped_files = 0 # count skipped files during collection due to --lf
@@ -350,7 +352,7 @@ def get_last_failed_paths(self) -> set[Path]:
350352 rootpath = self .config .rootpath
351353 result = set ()
352354 for nodeid in self .lastfailed :
353- path = rootpath / nodeid .split ( "::" )[ 0 ]
355+ path = rootpath / nodeid .path
354356 result .add (path )
355357 result .update (path .parents )
356358 return {x for x in result if x .exists ()}
@@ -362,18 +364,19 @@ def pytest_report_collectionfinish(self) -> str | None:
362364
363365 def pytest_runtest_logreport (self , report : TestReport ) -> None :
364366 if (report .when == "call" and report .passed ) or report .skipped :
365- self .lastfailed .pop (report .nodeid , None )
367+ self .lastfailed .pop (report .id , None )
366368 elif report .failed :
367- self .lastfailed [report .nodeid ] = True
369+ self .lastfailed [report .id ] = True
368370
369371 def pytest_collectreport (self , report : CollectReport ) -> None :
370372 passed = report .outcome in ("passed" , "skipped" )
371373 if passed :
372- if report .nodeid in self .lastfailed :
373- self .lastfailed .pop (report .nodeid )
374- self .lastfailed .update ((item .nodeid , True ) for item in report .result )
374+ report_id = report .id
375+ if report_id in self .lastfailed :
376+ self .lastfailed .pop (report_id )
377+ self .lastfailed .update ((item .id , True ) for item in report .result )
375378 else :
376- self .lastfailed [report .nodeid ] = True
379+ self .lastfailed [report .id ] = True
377380
378381 @hookimpl (wrapper = True , tryfirst = True )
379382 def pytest_collection_modifyitems (
@@ -388,7 +391,7 @@ def pytest_collection_modifyitems(
388391 previously_failed = []
389392 previously_passed = []
390393 for item in items :
391- if item .nodeid in self .lastfailed :
394+ if item .id in self .lastfailed :
392395 previously_failed .append (item )
393396 else :
394397 previously_passed .append (item )
@@ -433,9 +436,10 @@ def pytest_sessionfinish(self, session: Session) -> None:
433436 return
434437
435438 assert config .cache is not None
439+ current_lastfailed = {str (k ): v for k , v in self .lastfailed .items ()}
436440 saved_lastfailed = config .cache .get ("cache/lastfailed" , {})
437- if saved_lastfailed != self . lastfailed :
438- config .cache .set ("cache/lastfailed" , self . lastfailed )
441+ if saved_lastfailed != current_lastfailed :
442+ config .cache .set ("cache/lastfailed" , current_lastfailed )
439443
440444
441445class NFPlugin :
@@ -445,27 +449,29 @@ def __init__(self, config: Config) -> None:
445449 self .config = config
446450 self .active = config .option .newfirst
447451 assert config .cache is not None
448- self .cached_nodeids = set (config .cache .get ("cache/nodeids" , []))
452+ self .cached_nodeids : set [NodeId ] = {
453+ NodeId .parse (s ) for s in config .cache .get ("cache/nodeids" , [])
454+ }
449455
450456 @hookimpl (wrapper = True , tryfirst = True )
451457 def pytest_collection_modifyitems (self , items : list [nodes .Item ]) -> Generator [None ]:
452458 res = yield
453459
454460 if self .active :
455- new_items : dict [str , nodes .Item ] = {}
456- other_items : dict [str , nodes .Item ] = {}
461+ new_items : dict [NodeId , nodes .Item ] = {}
462+ other_items : dict [NodeId , nodes .Item ] = {}
457463 for item in items :
458- if item .nodeid not in self .cached_nodeids :
459- new_items [item .nodeid ] = item
464+ if item .id not in self .cached_nodeids :
465+ new_items [item .id ] = item
460466 else :
461- other_items [item .nodeid ] = item
467+ other_items [item .id ] = item
462468
463469 items [:] = self ._get_increasing_order (
464470 new_items .values ()
465471 ) + self ._get_increasing_order (other_items .values ())
466472 self .cached_nodeids .update (new_items )
467473 else :
468- self .cached_nodeids .update (item .nodeid for item in items )
474+ self .cached_nodeids .update (item .id for item in items )
469475
470476 return res
471477
@@ -481,7 +487,7 @@ def pytest_sessionfinish(self) -> None:
481487 return
482488
483489 assert config .cache is not None
484- config .cache .set ("cache/nodeids" , sorted (self .cached_nodeids ))
490+ config .cache .set ("cache/nodeids" , sorted (str ( n ) for n in self .cached_nodeids ))
485491
486492
487493def pytest_addoption (parser : Parser ) -> None :
0 commit comments