Fix for operation on closed file in faulthandler teardown (#11584)
This commit is contained in:
		
							parent
							
								
									fdb8bbf154
								
							
						
					
					
						commit
						a42530a09d
					
				| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					Handle an edge case where :data:`sys.stderr` and :data:`sys.__stderr__` might already be closed when :ref:`faulthandler` is tearing down.
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,8 @@ from _pytest.nodes import Item
 | 
				
			||||||
from _pytest.stash import StashKey
 | 
					from _pytest.stash import StashKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fault_handler_original_stderr_fd_key = StashKey[int]()
 | 
				
			||||||
fault_handler_stderr_fd_key = StashKey[int]()
 | 
					fault_handler_stderr_fd_key = StashKey[int]()
 | 
				
			||||||
fault_handler_originally_enabled_key = StashKey[bool]()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pytest_addoption(parser: Parser) -> None:
 | 
					def pytest_addoption(parser: Parser) -> None:
 | 
				
			||||||
| 
						 | 
					@ -24,8 +24,15 @@ def pytest_addoption(parser: Parser) -> None:
 | 
				
			||||||
def pytest_configure(config: Config) -> None:
 | 
					def pytest_configure(config: Config) -> None:
 | 
				
			||||||
    import faulthandler
 | 
					    import faulthandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    config.stash[fault_handler_stderr_fd_key] = os.dup(get_stderr_fileno())
 | 
					    # at teardown we want to restore the original faulthandler fileno
 | 
				
			||||||
    config.stash[fault_handler_originally_enabled_key] = faulthandler.is_enabled()
 | 
					    # but faulthandler has no api to return the original fileno
 | 
				
			||||||
 | 
					    # so here we stash the stderr fileno to be used at teardown
 | 
				
			||||||
 | 
					    # sys.stderr and sys.__stderr__ may be closed or patched during the session
 | 
				
			||||||
 | 
					    # so we can't rely on their values being good at that point (#11572).
 | 
				
			||||||
 | 
					    stderr_fileno = get_stderr_fileno()
 | 
				
			||||||
 | 
					    if faulthandler.is_enabled():
 | 
				
			||||||
 | 
					        config.stash[fault_handler_original_stderr_fd_key] = stderr_fileno
 | 
				
			||||||
 | 
					    config.stash[fault_handler_stderr_fd_key] = os.dup(stderr_fileno)
 | 
				
			||||||
    faulthandler.enable(file=config.stash[fault_handler_stderr_fd_key])
 | 
					    faulthandler.enable(file=config.stash[fault_handler_stderr_fd_key])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,9 +44,10 @@ def pytest_unconfigure(config: Config) -> None:
 | 
				
			||||||
    if fault_handler_stderr_fd_key in config.stash:
 | 
					    if fault_handler_stderr_fd_key in config.stash:
 | 
				
			||||||
        os.close(config.stash[fault_handler_stderr_fd_key])
 | 
					        os.close(config.stash[fault_handler_stderr_fd_key])
 | 
				
			||||||
        del config.stash[fault_handler_stderr_fd_key]
 | 
					        del config.stash[fault_handler_stderr_fd_key]
 | 
				
			||||||
    if config.stash.get(fault_handler_originally_enabled_key, False):
 | 
					    # Re-enable the faulthandler if it was originally enabled.
 | 
				
			||||||
        # Re-enable the faulthandler if it was originally enabled.
 | 
					    if fault_handler_original_stderr_fd_key in config.stash:
 | 
				
			||||||
        faulthandler.enable(file=get_stderr_fileno())
 | 
					        faulthandler.enable(config.stash[fault_handler_original_stderr_fd_key])
 | 
				
			||||||
 | 
					        del config.stash[fault_handler_original_stderr_fd_key]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_stderr_fileno() -> int:
 | 
					def get_stderr_fileno() -> int:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue