Source code for snakemake.linting
import textwrap
import shutil
import inspect
from abc import ABC, abstractmethod
from snakemake.logging import logger
NAME_PATTERN = "[a-zA-Z_][a-zA-Z_0-9]*"
[docs]
class Linter(ABC):
[docs]
def __init__(self, workflow, items):
self.items = items
self.workflow = workflow
def read_item(self, item):
return item
def lint(self, json=False):
json_lints = [] if json else None
linted = False
for item in self.items:
item_lints = [
lint
for lint_item in self.lints()
for lint in lint_item(self.read_item(item))
]
if not item_lints:
continue
linted = True
if json:
json_lints.append(
{
"for": self.item_desc_json(item),
"lints": [lint.__dict__ for lint in item_lints],
}
)
else:
logger.warning(
"Lints for {}:\n{}\n".format(
self.item_desc_plain(item),
"\n".join(map(" * {}".format, item_lints)),
)
)
return json_lints, linted
@abstractmethod
def item_desc_json(self, item):
pass
@abstractmethod
def item_desc_plain(self, item):
pass
def lints(self):
return (
method
for name, method in inspect.getmembers(self)
if name.startswith("lint_")
)
[docs]
class Lint:
[docs]
def __init__(self, title, body, links=None):
self.title = title
self.body = body
self.links = links or []
def __str__(self):
width, _ = shutil.get_terminal_size()
return "{}:\n{}\n Also see:\n{}".format(
self.title,
"\n".join(
map(" {}".format, textwrap.wrap(self.body, max(width - 6, 20)))
),
"\n".join(map(" {}".format, self.links)),
)