Skip to content

Commit e02373d

Browse files
committed
Merge branch 'main' of github.com:jmzhang1911/snakemake-logger-plugin-flowo into main
2 parents 8787149 + 036b857 commit e02373d

9 files changed

Lines changed: 738 additions & 591 deletions

File tree

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828

2929
- name: Build the package with uv
3030
run: |
31-
uv pip install -e .
31+
uv sync
3232
uv build
3333
3434
- name: Publish the package to PyPI

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"python-envs.defaultEnvManager": "ms-python.python:conda",
3+
"python-envs.defaultPackageManager": "ms-python.python:conda",
4+
"python-envs.pythonProjects": []
5+
}

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Snakemake Logger Plugin - Flowo
22

3-
A Snakemake logger plugin that stores workflow execution data in PostgreSQL, making your workflow management more efficient and fun! 🎉
3+
A Snakemake logger plugin designed to be used with **[FlowO](https://github.com/zhanghaomiao/flowo)** for real-time task monitoring, making workflow management simple, interactive, and fun! 🎉
4+
5+
**Demo page: [flowo online](https://zhanghaomiao.github.io/flowo)**
46

57
## 🎈 Features
68

pyproject.toml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "snakemake-logger-plugin-flowo"
7-
version = "0.1.2"
7+
version = "0.1.8"
88
description = "A Snakemake logger plugin that stores workflow execution data in PostgreSQL"
99
readme = "README.md"
1010
requires-python = ">=3.12"
@@ -23,8 +23,6 @@ classifiers = [
2323
"Topic :: Software Development :: Libraries :: Python Modules",
2424
]
2525
dependencies = [
26-
"numpy==1.26.4",
27-
"pandas==1.3.5",
2826
"psycopg2-binary>=2.9.9",
2927
"pydantic>=2.11.5",
3028
"pydantic-settings>=2.9.1",
@@ -41,9 +39,9 @@ flowo = "snakemake_logger_plugin_flowo:LogHandler"
4139
flowo = "snakemake_logger_plugin_flowo.__main__:main"
4240

4341
[project.urls]
44-
Homepage = "https://github.com/your-org/snakemake-logger-plugin-flowo"
45-
Repository = "https://github.com/your-org/snakemake-logger-plugin-flowo"
46-
Issues = "https://github.com/your-org/snakemake-logger-plugin-flowo/issues"
42+
Homepage = "https://github.com/jmzhang1911/snakemake-logger-plugin-flowo"
43+
Repository = "https://github.com/jmzhang1911/snakemake-logger-plugin-flowo"
44+
Issues = "https://github.com/jmzhang1911/snakemake-logger-plugin-flowo/issues"
4745

4846
[tool.hatch.build.targets.wheel]
4947
packages = ["snakemake_logger_plugin_flowo"]
@@ -52,6 +50,6 @@ packages = ["snakemake_logger_plugin_flowo"]
5250
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
5351
default = true
5452

55-
[[tool.uv.index]]
56-
url = "https://pypi.org/simple/"
57-
name = "pypi"
53+
# [[tool.uv.index]]
54+
# url = "https://pypi.org/simple/"
55+
# name = "pypi"

snakemake_logger_plugin_flowo/__init__.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66

77
from snakemake_interface_logger_plugins.base import LogHandlerBase
88
from .log_handler import PostgresqlLogHandler
9-
from pathlib import Path
10-
import logging
11-
from snakemake.logging import DefaultFormatter, DefaultFilter
129

1310
__version__ = "0.1.0"
1411

@@ -29,28 +26,6 @@ def __post_init__(self) -> None:
2926
)
3027
self.flowo_path_valid()
3128

32-
self.log_file_path = Path(self.context.get("logfile"))
33-
if not self.log_file_path.parent.exists():
34-
self.log_file_path.parent.mkdir(parents=True, exist_ok=True)
35-
self.file_handler = logging.FileHandler(self.log_file_path, encoding="utf-8")
36-
self.file_handler.setFormatter(
37-
DefaultFormatter(
38-
self.common_settings.quiet, self.common_settings.show_failed_logs
39-
)
40-
)
41-
self.file_handler.addFilter(
42-
DefaultFilter(
43-
self.common_settings.quiet,
44-
self.common_settings.debug_dag,
45-
self.common_settings.dryrun,
46-
self.common_settings.printshellcmds,
47-
)
48-
)
49-
self.file_handler.setLevel(
50-
logging.DEBUG if self.common_settings.verbose else logging.INFO
51-
)
52-
self.baseFilename = str(self.log_file_path)
53-
5429
@property
5530
def writes_to_stream(self) -> bool:
5631
"""Whether this plugin writes to stderr/stdout"""

snakemake_logger_plugin_flowo/log_handler.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
import logging
1111
from .config import settings
1212
from sqlalchemy import text
13+
from sqlalchemy import select, exists
1314

15+
from snakemake.logging import DefaultFormatter, DefaultFilter
1416

1517
from snakemake_interface_logger_plugins.common import LogEvent
1618
from snakemake_interface_logger_plugins.settings import OutputSettingsLoggerInterface
1719
from .models.workflow import Workflow
20+
from .models.job import Job
1821
from .models.enums import Status
1922
from .event_handlers import (
2023
EventHandler,
@@ -76,6 +79,36 @@ def __init__(
7679
**self._workflow_config,
7780
}
7881

82+
self.file_handler = self.file_handler_init()
83+
84+
def file_handler_init(self):
85+
self.log_file_path = Path(self.context.get("logfile"))
86+
87+
if not self.log_file_path.parent.exists():
88+
self.log_file_path.parent.mkdir(parents=True, exist_ok=True)
89+
90+
file_handler = logging.FileHandler(self.log_file_path, encoding="utf-8")
91+
file_handler.setFormatter(
92+
DefaultFormatter(
93+
self.common_settings.quiet, self.common_settings.show_failed_logs
94+
)
95+
)
96+
97+
file_handler.addFilter(
98+
DefaultFilter(
99+
self.common_settings.quiet,
100+
self.common_settings.debug_dag,
101+
self.common_settings.dryrun,
102+
self.common_settings.printshellcmds,
103+
)
104+
)
105+
106+
file_handler.setLevel(
107+
logging.DEBUG if self.common_settings.verbose else logging.INFO
108+
)
109+
110+
return file_handler
111+
79112
def db_connected(self) -> bool:
80113

81114
try:
@@ -179,16 +212,17 @@ def emit(self, record: LogRecord) -> None:
179212
self.file_handler.emit(record)
180213
try:
181214
event = getattr(record, "event", None)
215+
182216
if not event:
183217
return
184218
event_value = event.value if hasattr(event, "value") else str(event).lower()
185219
handler = self.event_handlers.get(event_value)
186220
if not handler or self.context.get("dryrun"):
187221
return
188-
189222
with self.session_scope() as session:
190223
handler.handle(record, session, self.context)
191-
except Exception:
224+
except Exception as e:
225+
logger.info(e)
192226
self.handleError(record)
193227

194228
def close(self) -> None:
@@ -200,9 +234,21 @@ def close(self) -> None:
200234
workflow = session.query(Workflow).get(
201235
self.context["current_workflow_id"]
202236
)
203-
if workflow and workflow.status != Status.ERROR:
204-
workflow.status = Status.SUCCESS
205-
workflow.end_time = datetime.now()
237+
if workflow:
238+
239+
stmt = select(
240+
exists().where(
241+
Job.workflow_id == workflow.id,
242+
Job.status == Status.ERROR,
243+
)
244+
)
245+
has_error = session.scalar(stmt)
246+
if has_error:
247+
workflow.status = Status.ERROR
248+
else:
249+
workflow.status = Status.SUCCESS
250+
workflow.end_time = datetime.now()
251+
206252
except Exception as e:
207253
self.handleError(
208254
logging.LogRecord(
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)