Skip to content

Commit 4709fcf

Browse files
Merge pull request #253 from snakemake/feat/inputflags
feat: adapt to Snakemake 8 and 9 (add inputflags, outputflags, storage directive support, remove version and subworkflow directive support)
2 parents 7223a2b + 048161e commit 4709fcf

File tree

8 files changed

+45
-1618
lines changed

8 files changed

+45
-1618
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,4 @@ tmp_work
141141
.python-version
142142
tags
143143
.vimspector.json
144+
poetry.lock

Diff for: poetry.lock

-1,600
This file was deleted.

Diff for: pyproject.toml

+7-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ keywords = ["python", "snakemake", "code", "formatter", "parser", "workflow", "m
1414
snakefmt = 'snakefmt.snakefmt:main'
1515

1616
[tool.poetry.dependencies]
17-
python = "^3.9"
17+
python = "^3.11"
1818
click = "^8.0.0"
1919
black = "^24.3.0"
2020
toml = "^0.10.2"
@@ -24,7 +24,12 @@ importlib_metadata = {version = ">=1.7.0,<5.0", python = "<3.8"}
2424
pytest = "^7.4.4"
2525
pytest-cov = "^4.1.0"
2626
flake8 = "^7.0"
27-
snakemake = "<8.0"
27+
# Always set this to the latest Snakemake version with grammar changes.
28+
# This way, the testcases for grammar completeness ensure that the formatter is always
29+
# up-to-date with the latest Snakemake.
30+
# TODO: implement a bot action that auto-creates a bumping PR on every Snakemake
31+
# release.
32+
snakemake = ">=9.1.1"
2833
isort = "^5.1.0"
2934
pynvim = "~0.4.3"
3035

Diff for: snakefmt/formatter.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ def format_params(self, parameters: ParameterSyntax) -> str:
371371
if p_class is InlineSingleParam:
372372
inline_fmting = True
373373

374-
result = f"{used_indent}{parameters.keyword_name}:"
374+
result = f"{used_indent}{parameters.keyword_line}:"
375375
if inline_fmting:
376376
result += " "
377377
prepended_comments = ""

Diff for: snakefmt/parser/grammar.py

+5-10
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ class PythonCode(Vocabulary):
3434
threads=Context(None, InlineSingleParam),
3535
resources=Context(None, ParamList),
3636
priority=Context(None, InlineSingleParam),
37-
version=Context(None, SingleParam),
3837
log=Context(None, ParamList),
3938
message=Context(None, SingleParam),
4039
benchmark=Context(None, SingleParam),
@@ -79,14 +78,7 @@ class SnakeModule(Vocabulary):
7978
meta_wrapper=Context(None, SingleParam),
8079
prefix=Context(None, SingleParam),
8180
replace_prefix=Context(None, SingleParam),
82-
)
83-
84-
85-
class SnakeSubworkflow(Vocabulary):
86-
spec = dict(
87-
snakefile=Context(None, SingleParam),
88-
workdir=Context(None, SingleParam),
89-
configfile=Context(None, SingleParam),
81+
name=Context(None, InlineSingleParam),
9082
)
9183

9284

@@ -102,7 +94,6 @@ class SnakeGlobal(Vocabulary):
10294
ruleorder=Context(None, InlineSingleParam),
10395
rule=Context(SnakeRule, KeywordSyntax),
10496
checkpoint=Context(SnakeRule, KeywordSyntax),
105-
subworkflow=Context(SnakeSubworkflow, KeywordSyntax),
10697
localrules=Context(None, NoKeyParamList),
10798
onstart=Context(PythonCode, KeywordSyntax),
10899
onsuccess=Context(PythonCode, KeywordSyntax),
@@ -112,7 +103,11 @@ class SnakeGlobal(Vocabulary):
112103
container=Context(None, InlineSingleParam),
113104
containerized=Context(None, InlineSingleParam),
114105
scattergather=Context(None, ParamList),
106+
inputflags=Context(None, NoKeyParamList),
107+
outputflags=Context(None, NoKeyParamList),
115108
module=Context(SnakeModule, KeywordSyntax),
116109
use=Context(SnakeUseRule, KeywordSyntax),
117110
resource_scopes=Context(None, KeywordSyntax),
111+
conda=Context(None, InlineSingleParam),
112+
storage=Context(None, ParamList),
118113
)

Diff for: snakefmt/parser/syntax.py

+16
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,22 @@ def __init__(
365365
def validate_keyword_line(self, snakefile: TokenIterator):
366366
self.token = next(snakefile)
367367

368+
if self.keyword_name == "storage":
369+
self.validate_named_keyword_line(snakefile)
370+
else:
371+
self.validate_anonymous_keyword_line(snakefile)
372+
373+
def validate_named_keyword_line(self, snakefile: TokenIterator):
374+
if not is_colon(self.token):
375+
if self.token.type != tokenize.NAME:
376+
NotAnIdentifierError(self.line_nb, self.token.string, self.keyword_line)
377+
self.keyword_line += f" {self.token.string}"
378+
self.token = next(snakefile)
379+
if not is_colon(self.token):
380+
ColonError(self.line_nb, self.token.string, self.keyword_line)
381+
self.token = next(snakefile)
382+
383+
def validate_anonymous_keyword_line(self, snakefile: TokenIterator):
368384
if not is_colon(self.token):
369385
ColonError(self.line_nb, self.token.string, self.keyword_line)
370386
self.token = next(snakefile)

Diff for: tests/test_formatter.py

+15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
errors arise, as tested in test_parser.py.
55
"""
66

7+
import textwrap
78
from io import StringIO
89
from unittest import mock
910

@@ -1457,3 +1458,17 @@ def test_shell_indention_long_line(self):
14571458
formatter = setup_formatter(snakecode)
14581459

14591460
assert formatter.get_formatted() == snakecode
1461+
1462+
1463+
class TestStorage:
1464+
def test_storage(self):
1465+
code = textwrap.dedent(
1466+
"""
1467+
storage http_local:
1468+
provider="http",
1469+
keep_local=True,
1470+
"""
1471+
)
1472+
formatter = setup_formatter(code)
1473+
1474+
assert formatter.get_formatted() == code

Diff for: tests/test_grammar.py

-5
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ def test_module_context_completeness(self):
3131
existing_keywords = set(grammar.SnakeModule.spec)
3232
self.check_completeness(target_keywords, existing_keywords)
3333

34-
def test_subworkflow_context_completeness(self):
35-
target_keywords = set(parser.Subworkflow.subautomata)
36-
existing_keywords = set(grammar.SnakeSubworkflow.spec)
37-
self.check_completeness(target_keywords, existing_keywords)
38-
3934
def test_use_rule_context_completeness(self):
4035
target_keywords = set(parser.UseRule.subautomata)
4136
existing_keywords = set(grammar.SnakeUseRule.spec)

0 commit comments

Comments
 (0)