Skip to content

Commit c16e918

Browse files
committed
rm custom logging
1 parent bf42ca0 commit c16e918

26 files changed

+57
-124
lines changed

harpy/commands/view.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import rich_click as click
1313
from rich.console import Console
1414
from rich.panel import Panel
15+
from rich.prompt import Prompt
16+
from rich.table import Table
1517
from rich import print as rprint
16-
from harpy.common.printing import print_error
18+
from harpy.common.printing import harpy_table, print_error
1719
from harpy.common.file_ops import is_gzip
1820

1921
def check_terminal_colors():
@@ -41,7 +43,7 @@ def check_terminal_colors():
4143

4244
def parse_file(infile: str):
4345
'''
44-
take a list of input file name, get the most recent by modificiation time, and print it via pygmentized less
46+
take an input file name, get the most recent by modificiation time, and print it via pygmentized less
4547
returns a string of the file that was viewed
4648
'''
4749
if not os.access(infile, os.R_OK):
@@ -162,14 +164,15 @@ def environments(program):
162164
return
163165

164166
@click.command(no_args_is_help = True, context_settings={"allow_interspersed_args" : False})
167+
@click.option("-c", "--choose", is_flag=True, default=False, help = "From one from all the logs")
165168
@click.argument('directory', required=True, type=click.Path(exists=True, file_okay=False), nargs=1)
166-
def log(directory):
169+
def log(directory, choose):
167170
"""
168171
View a workflow's last log file
169172
170173
The log file contains everything Snakemake printed during runtime.
171174
The only required input is the output folder previously created by Harpy where you can find
172-
`logs/snakemake/`. Navigate with the typical `less` keyboard bindings, e.g.:
175+
`.snakemake/log`. Navigate with the typical `less` keyboard bindings, e.g.:
173176
174177
| key | function |
175178
| :---------------------- | :------------------------- |
@@ -178,7 +181,7 @@ def log(directory):
178181
| `/` + `pattern` | search for `pattern` |
179182
| `q` | exit |
180183
"""
181-
err_dir = os.path.join(directory, "logs", "snakemake")
184+
err_dir = os.path.join(directory, ".snakemake", "log")
182185
err_file = "There are no log files"
183186
if not os.path.exists(err_dir):
184187
print_error(
@@ -191,7 +194,30 @@ def log(directory):
191194
"files not found",
192195
f"{err_file} in [blue]{err_dir}[/]. Please check that this is the correct folder."
193196
)
194-
target_file = sorted(files, key = os.path.getmtime)[-1]
197+
198+
files = sorted(files, key = os.path.getmtime, reverse = True)
199+
if choose:
200+
console = Console()
201+
console.print()
202+
console.rule('Snakemake Log Files', style = "green")
203+
_tb = harpy_table()
204+
_tb.add_column("Number", justify="left", style="bold green", no_wrap=True)
205+
_tb.add_column("File", justify="left")
206+
for i,j in enumerate(files,1):
207+
_tb.add_row(str(i), os.path.basename(j))
208+
console.print(_tb)
209+
console.rule('[dim]sorted newest (top) to oldest (bottom)[/]', style = 'dim')
210+
selection = Prompt.ask(
211+
"\n[bold blue]Select a log file by number[/]",
212+
choices=list(str(i) for i in range(1,len(files) + 1)),
213+
show_choices=False
214+
)
215+
216+
selected_idx = int(selection) - 1
217+
target_file = files[selected_idx]
218+
else:
219+
target_file = files[0]
220+
195221
parse_file(target_file)
196222
rprint(
197223
Panel(

harpy/common/file_ops.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ def gzip_file(infile: str) -> None:
2222
shutil.copyfileobj(f_in, f_out)
2323
os.remove(infile)
2424

25+
def last_sm_log(directory) -> str:
26+
'''Find and return the name of the last snakemake log file, otherwise return an empty string'''
27+
err_dir = os.path.join(directory, ".snakemake", "log")
28+
if not os.path.exists(err_dir) or not os.path.exists(directory):
29+
return ""
30+
files = [i for i in glob.iglob(f"{err_dir}/*.log*")]
31+
return os.path.basename(sorted(files, key = os.path.getmtime)[-1])
32+
2533
def purge_empty_logs(output_directory):
2634
"""scan target_dir and remove empty files, then scan it again and remove empty directories"""
2735
for logfile in glob.glob(f"{output_directory}/logs/**/*", recursive = True):

harpy/common/launch.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from rich import box
99
from rich.syntax import Syntax
1010
from rich.table import Table
11-
from harpy.common.file_ops import gzip_file, purge_empty_logs
11+
from harpy.common.file_ops import last_sm_log, purge_empty_logs
1212
from harpy.common.printing import CONSOLE, print_onerror, print_setup_error
1313
from harpy.common.progress import harpy_progressbar, harpy_pulsebar, harpy_progresspanel
1414

@@ -92,7 +92,7 @@ def highlight_params(text: str):
9292
return f"\n[blue]{text}[/]"
9393
return text
9494

95-
def launch_snakemake(sm_args, outdir, sm_logfile, quiet, CONSOLE = CONSOLE):
95+
def launch_snakemake(sm_args, outdir, quiet, CONSOLE = CONSOLE):
9696
"""launch snakemake with the given commands"""
9797
exitcode = None
9898
sm_start = datetime.now()
@@ -227,7 +227,7 @@ def launch_snakemake(sm_args, outdir, sm_logfile, quiet, CONSOLE = CONSOLE):
227227
if exitcode in (1,2):
228228
print_setup_error(exitcode)
229229
elif exitcode == 3:
230-
print_onerror(os.path.join(os.path.basename(outdir), sm_logfile), datetime.now() - sm_start)
230+
print_onerror(last_sm_log(outdir), datetime.now() - sm_start)
231231

232232
CONSOLE.tab_size = 4
233233
CONSOLE._highlight = False
@@ -302,6 +302,5 @@ def launch_snakemake(sm_args, outdir, sm_logfile, quiet, CONSOLE = CONSOLE):
302302
CONSOLE.rule("[bold]Terminating Harpy", style = "yellow")
303303
process.terminate()
304304
process.wait()
305-
gzip_file(os.path.join(outdir,sm_logfile))
306305
purge_empty_logs(outdir)
307306
sys.exit(1)

harpy/common/printing.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
CONSOLE = Console(stderr=True, log_path=False)
1414

15+
def harpy_table(title = None, caption = None):
16+
'''Insantiate a generic but standardized table style for harpy output'''
17+
return Table(title = title, caption = caption, show_header=False,pad_edge=False, show_edge=False, padding = (0,0), box=box.SIMPLE)
18+
1519
def print_error(
1620
errortitle: str,
1721
errortext: RenderableType|str,
@@ -106,7 +110,7 @@ def print_onerror(logfile: str, time) -> None:
106110
minutes = (seconds % 3600) // 60
107111
seconds = seconds % 60
108112
time_text = f"{days} days, {hours} hours, {minutes} minutes, {seconds} seconds"
109-
datatable = Table(show_header=False,pad_edge=False, show_edge=False, padding = (0,0), box=box.SIMPLE)
113+
datatable = harpy_table()
110114
datatable.add_column("detail", justify="left", style="red", no_wrap=True)
111115
datatable.add_column("value", justify="left")
112116
datatable.add_row("Duration:", time_text)
@@ -117,13 +121,7 @@ def print_onerror(logfile: str, time) -> None:
117121
CONSOLE.rule("[bold]Where Error Occurred", style = "red")
118122

119123
def print_shellcmd_simple(text):
120-
_table = Table(
121-
show_header=False,
122-
pad_edge=False,
123-
show_edge=False,
124-
padding=(0,0),
125-
box=box.SIMPLE,
126-
)
124+
_table = harpy_table()
127125
_table.add_column("Lpadding", justify="left")
128126
_table.add_column("shell", justify="left")
129127
_table.add_column("Rpadding", justify="left")
@@ -138,7 +136,7 @@ def workflow_info(*arg: tuple[str, str | int | float]|None) -> Table:
138136
Accepts an unlimited number of length-2 lists or tuples and returns a rich.Table with the value of the first indices as the row names and the second indices as the values
139137
Use None instead of a list to ignore that entry (useful for conditionals). The second value will always be converted to a string.
140138
"""
141-
table = Table(show_header=False,pad_edge=False, show_edge=False, padding = (0,0), box=box.SIMPLE)
139+
table = harpy_table()
142140
table.add_column("detail", justify="left", style="light_steel_blue", no_wrap=True)
143141
table.add_column("value", justify="left")
144142
for i in arg:

harpy/common/workflow.py

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Contains the WorkFlow class"""
22

33
from datetime import datetime
4-
import glob
54
import importlib.resources as resources
65
import os
76
import shutil
@@ -10,11 +9,10 @@
109
import urllib.request
1110
import urllib.error
1211
import yaml
13-
from rich import box
1412
from rich.table import Table
1513
from harpy.common.conda import create_conda_recipes
16-
from harpy.common.file_ops import filepath, gzip_file, purge_empty_logs
17-
from harpy.common.printing import CONSOLE, print_error
14+
from harpy.common.file_ops import filepath, last_sm_log, purge_empty_logs
15+
from harpy.common.printing import CONSOLE, harpy_table, print_error
1816
from harpy.common.launch import launch_snakemake
1917
from harpy.common.summaries import Summary
2018

@@ -30,7 +28,6 @@ def __init__(self, name, snakefile, outdir, container, quiet, inputdir = False):
3028
self.name: str = name
3129
self.output_directory: str = outdir
3230
self.workflow_directory = os.path.join(outdir, 'workflow')
33-
self.snakemake_logfile: str = self.snakemake_log(outdir, name)
3431
self.snakemake_cmd_absolute: str = ""
3532
self.snakemake_cmd_relative: str = ""
3633
self.snakefile: str = snakefile
@@ -48,16 +45,6 @@ def __init__(self, name, snakefile, outdir, container, quiet, inputdir = False):
4845
self.summary: str = name.replace("_",".").replace(" ",".") + ".summary"
4946
self.summary_text: str = ""
5047

51-
def snakemake_log(self, outdir: str, workflow: str) -> str:
52-
"""Return a snakemake logfile name. Iterates logfile run number if one exists."""
53-
attempts = glob.glob(os.path.join(outdir, "logs", "snakemake", "*.log*"))
54-
timestamp = datetime.now().strftime("%d_%m_%Y") + ".log"
55-
if not attempts:
56-
os.makedirs(os.path.join(outdir, "logs", "snakemake"), exist_ok=True)
57-
return os.path.join("logs", "snakemake", f"{workflow}.1.{timestamp}")
58-
increment = sorted([int(i.split(".")[1]) for i in attempts])[-1] + 1
59-
return os.path.join("logs", "snakemake", f"{workflow}.{increment}.{timestamp}")
60-
6148
def setup_snakemake(self, threads: int, hpc: str|None = None, sm_extra: str|None = None):
6249
"""
6350
Sets up the snakemake command based on hpc, threads, and extra snakemake params.
@@ -214,7 +201,6 @@ def write_workflow_config(self) -> None:
214201
are expected to be a dict
215202
"""
216203
self.config["snakemake"] = {
217-
"log" : self.snakemake_logfile,
218204
"absolute": self.snakemake_cmd_absolute,
219205
"relative": self.snakemake_cmd_relative,
220206
"conda_envs": self.conda
@@ -249,13 +235,15 @@ def print_onsuccess(self):
249235
return
250236
_relpath = os.path.relpath(self.output_directory)
251237
time_text = self.time_elapsed()
252-
datatable = Table(show_header=False,pad_edge=False, show_edge=False, padding = (0,0), box=box.SIMPLE)
238+
datatable = harpy_table()
253239
datatable.add_column("detail", justify="left", style="green", no_wrap=True)
254240
datatable.add_column("value", justify="left")
255241
datatable.add_row("Duration:", time_text)
256242
if self.summary:
257243
datatable.add_row("Summary: ", os.path.join(_relpath, "workflow", os.path.basename(self.summary)))
258-
datatable.add_row("Workflow Log:", os.path.join(_relpath, "logs", "snakemake", os.path.basename(f"{self.snakemake_logfile}.gz")))
244+
_smlog = last_sm_log(self.output_directory)
245+
if _smlog:
246+
datatable.add_row("Workflow Log:", os.path.join(_relpath, ".snakemake", 'log', _smlog))
259247
CONSOLE.rule("[bold]Workflow Finished[/] [default dim]" + _time.strftime('%d %b %Y @ %H:%M'), style="green")
260248
CONSOLE.print(datatable)
261249

@@ -283,12 +271,10 @@ def launch(self, absolute:bool = False):
283271
cmd = self.snakemake_cmd_absolute if absolute else self.snakemake_cmd_relative
284272

285273
try:
286-
launch_snakemake(cmd, self.output_directory, self.snakemake_logfile, self.quiet)
274+
launch_snakemake(cmd, self.output_directory, self.quiet)
287275
finally:
288276
with open(os.path.join(self.output_directory, "workflow", f"{self.name.replace('_','.')}.summary"), "w") as f_out:
289277
f_out.write(Summary(self.config).get_text())
290278
self.purge_empty_logs()
291-
if os.path.exists(self.snakemake_logfile):
292-
gzip_file(os.path.join(self.output_directory, self.snakemake_logfile))
293279

294280
self.print_onsuccess()

harpy/snakefiles/align_bwa.smk

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import os
22
import re
3-
import logging
43

5-
onstart:
6-
logfile_handler = logger_manager._default_filehandler(config["snakemake"]["log"])
7-
logger.addHandler(logfile_handler)
84
wildcard_constraints:
95
sample = r"[a-zA-Z0-9._-]+"
106

harpy/snakefiles/align_strobe.smk

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import os
22
import re
3-
import logging
43

5-
onstart:
6-
logfile_handler = logger_manager._default_filehandler(config["snakemake"]["log"])
7-
logger.addHandler(logfile_handler)
84
wildcard_constraints:
95
sample = r"[a-zA-Z0-9._-]+"
106

harpy/snakefiles/assembly.smk

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import os
2-
import logging
32

4-
onstart:
5-
logfile_handler = logger_manager._default_filehandler(config["snakemake"]["log"])
6-
logger.addHandler(logfile_handler)
73

84
FQ1 = config["inputs"]["fastq_r1"]
95
FQ2 = config["inputs"]["fastq_r2"]

harpy/snakefiles/deconvolve.smk

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import os
22
import re
3-
import logging
43

5-
onstart:
6-
logfile_handler = logger_manager._default_filehandler(config["snakemake"]["log"])
7-
logger.addHandler(logfile_handler)
84
wildcard_constraints:
95
sample = r"[a-zA-Z0-9._-]+"
106

harpy/snakefiles/demultiplex_meier2021.smk

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import os
2-
import logging
32

4-
onstart:
5-
logfile_handler = logger_manager._default_filehandler(config["snakemake"]["log"])
6-
logger.addHandler(logfile_handler)
73
wildcard_constraints:
84
sample = r"[a-zA-Z0-9._-]+",
95
FR = r"[12]",

0 commit comments

Comments
 (0)