Skip to content

Commit

Permalink
fix: Prevent binary log files to crash snakemake execution with `show…
Browse files Browse the repository at this point in the history
…-failed-logs` (#2827)

### Description

As described in #2826 currently the whole snakemake execution crashes if
a log file is binary and `show-failed-logs` is used.

This fix prevents the crash by capturing the `UnicodeDecodeError` and
returning an error message that the log file is not a text instead.

### QC

* [x] The PR contains a test case for the changes or the changes are
already covered by an existing test case.
* [x] The documentation (`docs/`) is updated to reflect the changes or
this is not necessary (e.g. if the change does neither modify the
language nor the behavior or functionalities of Snakemake).

---------

Co-authored-by: Vito Zanotelli <vito.zanotelli@gmail.com>
  • Loading branch information
votti and Vito Zanotelli committed Apr 28, 2024
1 parent ac144fc commit 8a80bda
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 0 deletions.
3 changes: 3 additions & 0 deletions snakemake/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@ def show_logs(logs):
except FileNotFoundError:
yield f"Logfile {f} not found."
return
except UnicodeDecodeError:
yield f"Logfile {f} is not a text file."
return
lines = content.splitlines()
logfile_header = f"Logfile {f}:"
if not lines:
Expand Down
12 changes: 12 additions & 0 deletions tests/test_issue2826_failed_binary_logs/Snakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
rule:
log:
'log.bin'
run:
import pickle
with open(log[0], 'wb') as f:
# Write anything binary to the file
# that cannot be interpreted as unicode
# dumping the log object was an easy way to do this
pickle.dump(log, f)
# make this test fail
a
12 changes: 12 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,18 @@ def test_dup_out_patterns():
run(dpath("test_dup_out_patterns"), shouldfail=True)


def test_issue2826_failed_binary_logs():
"""Show how a binary log file crushes `show_logs`
The log file in this test is a binary file.
The `show_failed_logs` is activated by default using `run`,
thus `show_logs` will be called at the end of the test.
Thus this test will check if `show_logs` is able to handle
the binary log file.
"""
run(dpath("test_issue2826_failed_binary_logs"), shouldfail=True)


# TODO reactivate once generic cluster executor is properly released
# @skip_on_windows
# def test_restartable_job_cmd_exit_1_no_restart():
Expand Down

0 comments on commit 8a80bda

Please sign in to comment.