Description
What's the problem this feature will solve?
set_log_path() currently overwrites existing log-files.
I would like to add fixtures that produce e.g. a logfile per module (scope = 'module') or for selected tests (scope = 'function').
Using set_log_path() is great for this, however the old path (if it existed) cannot be restored when upon fixture teardown. This does not allow the fixture to be e.g. combined with the --log-file commandline option for tests not using the fixture.
Describe the solution you'd like
Thus I propose to return the old path and to add an option to append to the file instead of overwriting it.
Alternative Solutions
I have tried different things, however using the set_log_path() seems the most simple way to achieve this.
Additional context
Here are the proposed changes to set_log_path:
def set_log_path(self, fname: str, append=False) -> None: """Set the filename parameter for Logging.FileHandler(). Creates parent directory if it does not exist. .. warning:: This is an experimental API. """ fpath = Path(fname) if not fpath.is_absolute(): fpath = self._config.rootpath / fpath if not fpath.parent.exists(): fpath.parent.mkdir(exist_ok=True, parents=True) stream = fpath.open(mode="w" if not append else "a", encoding="UTF-8") if sys.version_info >= (3, 7): old_stream = self.log_file_handler.setStream(stream) else: old_stream = self.log_file_handler.stream self.log_file_handler.acquire() try: self.log_file_handler.flush() self.log_file_handler.stream = stream finally: self.log_file_handler.release() old_path = None if old_stream: old_path = os.path.abspath(old_stream.name) old_stream.close() return old_path
Example of application for a fixture generating one log file per test:
It allows to write a specific logfile for selected tests and at the same time still allows the usage of --log-file from the commandline to work on all other tests. (attention, I added a pytestconfig.option.logdir
option)
@pytest.fixture(scope='function') def logfile_per_test(request, pytestconfig): """ A fixture that creates a logfile per test/ function call. If the function is parametrized, one logfile per call(!) is created. """ logging_plugin=request.config.pluginmanager.get_plugin("logging-plugin") filename=os.path.join(pytestconfig.option.logdir, request.module.__name__ + '__' + request.node.name.replace('[','__').replace(']', '__') +".log") oldfile = logging_plugin.set_log_path(filename, append=False) # this overwrites the logfile! # write some intitial info to the logfile log = logging.getLogger(request.module.__name__) log.info(f"========= {request.module.__name__}.{request.node.name} =======================") yield # write some closing info to the logfile log.info(f"========= finished {request.module.__name__}.{request.node.name} ==============") # restore the old logfile, in case there had been one, and append to it if oldfile: logging_plugin.set_log_path(oldfile, append=True) # this further appends to the existing logfile!