3131import  io 
3232import  os 
3333import  json 
34+ import  uuid 
3435import  shutil 
3536import  hashlib 
3637import  logging 
@@ -216,6 +217,12 @@ def pytest_addoption(parser):
216217    parser .addini (option , help = msg )
217218
218219
220+ class  XdistPlugin :
221+     def  pytest_configure_node (self , node ):
222+         node .workerinput ["pytest_mpl_uid" ] =  node .config .pytest_mpl_uid 
223+         node .workerinput ["pytest_mpl_results_dir" ] =  node .config .pytest_mpl_results_dir 
224+ 
225+ 
219226def  pytest_configure (config ):
220227
221228    config .addinivalue_line (
@@ -288,12 +295,20 @@ def get_cli_or_ini(name, default=None):
288295            if  not  _hash_library_from_cli :
289296                hash_library  =  os .path .abspath (hash_library )
290297
298+         if  not  hasattr (config , "workerinput" ):
299+             uid  =  uuid .uuid4 ().hex 
300+             results_dir_path  =  results_dir  or  tempfile .mkdtemp ()
301+             config .pytest_mpl_uid  =  uid 
302+             config .pytest_mpl_results_dir  =  results_dir_path 
303+ 
304+         if  config .pluginmanager .hasplugin ("xdist" ):
305+             config .pluginmanager .register (XdistPlugin (), name = "pytest_mpl_xdist_plugin" )
306+ 
291307        plugin  =  ImageComparison (
292308            config ,
293309            baseline_dir = baseline_dir ,
294310            baseline_relative_dir = baseline_relative_dir ,
295311            generate_dir = generate_dir ,
296-             results_dir = results_dir ,
297312            hash_library = hash_library ,
298313            generate_hash_library = generate_hash_lib ,
299314            generate_summary = generate_summary ,
@@ -356,7 +371,6 @@ def __init__(
356371        baseline_dir = None ,
357372        baseline_relative_dir = None ,
358373        generate_dir = None ,
359-         results_dir = None ,
360374        hash_library = None ,
361375        generate_hash_library = None ,
362376        generate_summary = None ,
@@ -372,7 +386,7 @@ def __init__(
372386        self .baseline_dir  =  baseline_dir 
373387        self .baseline_relative_dir  =  path_is_not_none (baseline_relative_dir )
374388        self .generate_dir  =  path_is_not_none (generate_dir )
375-         self .results_dir  =  path_is_not_none ( results_dir ) 
389+         self .results_dir  =  None 
376390        self .hash_library  =  path_is_not_none (hash_library )
377391        self ._hash_library_from_cli  =  _hash_library_from_cli   # for backwards compatibility 
378392        self .generate_hash_library  =  path_is_not_none (generate_hash_library )
@@ -394,11 +408,6 @@ def __init__(
394408        self .deterministic  =  deterministic 
395409        self .default_backend  =  default_backend 
396410
397-         # Generate the containing dir for all test results 
398-         if  not  self .results_dir :
399-             self .results_dir  =  Path (tempfile .mkdtemp (dir = self .results_dir ))
400-         self .results_dir .mkdir (parents = True , exist_ok = True )
401- 
402411        # Decide what to call the downloadable results hash library 
403412        if  self .hash_library  is  not   None :
404413            self .results_hash_library_name  =  self .hash_library .name 
@@ -411,6 +420,14 @@ def __init__(
411420        self ._test_stats  =  None 
412421        self .return_value  =  {}
413422
423+     def  pytest_sessionstart (self , session ):
424+         config  =  session .config 
425+         if  hasattr (config , "workerinput" ):
426+             config .pytest_mpl_uid  =  config .workerinput ["pytest_mpl_uid" ]
427+             config .pytest_mpl_results_dir  =  config .workerinput ["pytest_mpl_results_dir" ]
428+         self .results_dir  =  Path (config .pytest_mpl_results_dir )
429+         self .results_dir .mkdir (parents = True , exist_ok = True )
430+ 
414431    def  get_logger (self ):
415432        # configure a separate logger for this pluggin which is independent 
416433        # of the options that are configured for pytest or for the code that 
@@ -933,15 +950,20 @@ def pytest_runtest_call(self, item):  # noqa
933950                    result ._excinfo  =  (type (e ), e , e .__traceback__ )
934951
935952    def  generate_summary_json (self ):
936-         json_file  =  self .results_dir  /  'results.json' 
953+         filename  =  "results.json" 
954+         if  hasattr (self .config , "workerinput" ):
955+             worker_id  =  os .environ .get ("PYTEST_XDIST_WORKER" )
956+             filename  =  f"results-xdist-{ self .config .pytest_mpl_uid }  -{ worker_id }  .json" 
957+         json_file  =  self .results_dir  /  filename 
937958        with  open (json_file , 'w' ) as  f :
938959            json .dump (self ._test_results , f , indent = 2 )
939960        return  json_file 
940961
941-     def  pytest_unconfigure (self , config ):
962+     def  pytest_sessionfinish (self , session ):
942963        """ 
943964        Save out the hash library at the end of the run. 
944965        """ 
966+         config  =  session .config 
945967        result_hash_library  =  self .results_dir  /  (self .results_hash_library_name  or  "temp.json" )
946968        if  self .generate_hash_library  is  not   None :
947969            hash_library_path  =  Path (config .rootdir ) /  self .generate_hash_library 
@@ -960,10 +982,24 @@ def pytest_unconfigure(self, config):
960982                    json .dump (result_hashes , fp , indent = 2 )
961983
962984        if  self .generate_summary :
985+             try :
986+                 import  xdist 
987+                 is_xdist_controller  =  xdist .is_xdist_controller (session )
988+                 is_xdist_worker  =  xdist .is_xdist_worker (session )
989+             except  ImportError :
990+                 is_xdist_controller  =  False 
991+                 is_xdist_worker  =  False 
963992            kwargs  =  {}
964993            if  'json'  in  self .generate_summary :
994+                 if  is_xdist_controller :
995+                     uid  =  config .pytest_mpl_uid 
996+                     for  worker_results  in  self .results_dir .glob (f"results-xdist-{ uid }  -*.json" ):
997+                         with  worker_results .open () as  f :
998+                             self ._test_results .update (json .load (f ))
965999                summary  =  self .generate_summary_json ()
9661000                print (f"A JSON report can be found at: { summary }  " )
1001+             if  is_xdist_worker :
1002+                 return 
9671003            if  result_hash_library .exists ():  # link to it in the HTML 
9681004                kwargs ["hash_library" ] =  result_hash_library .name 
9691005            if  'html'  in  self .generate_summary :
0 commit comments