Skip to content

Commit 01f2af9

Browse files
committed
Add -r/--recursive options to planemo lint.
Shed lint with --tools will always work this way since I think the Tool Shed is pretty aggressive about finding tools. Mentioning #139 - though this doesn't implement the multiple paths on the command-line API change.
1 parent 2135f12 commit 01f2af9

File tree

9 files changed

+95
-24
lines changed

9 files changed

+95
-24
lines changed

planemo/commands/cmd_lint.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515
@options.fail_level_option()
1616
@options.skip_option()
1717
@options.lint_xsd_option()
18+
@options.recursive_option()
1819
@pass_context
1920
def cli(ctx, path, **kwds):
2021
"""Check specified tool(s) for common errors and adherence to best
2122
practices.
2223
"""
2324
lint_args = build_lint_args(ctx, **kwds)
24-
exit = lint_tools_on_path(ctx, path, lint_args)
25+
exit = lint_tools_on_path(
26+
ctx,
27+
path,
28+
lint_args,
29+
recursive=kwds["recursive"]
30+
)
2531
sys.exit(exit)

planemo/options.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,15 @@ def fail_level_option():
298298

299299

300300
def recursive_shed_option():
301+
return recursive_option(
302+
"Recursively perform command for nested repository directories.",
303+
)
304+
305+
306+
def recursive_option(help="Recursively perform command for subdirectories."):
301307
return click.option(
302308
'-r',
303309
'--recursive',
304310
is_flag=True,
305-
help="Recursively perform command for nested repository directories.",
311+
help=help,
306312
)

planemo/shed_lint.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def lint_repository(ctx, path, **kwds):
6262
path,
6363
)
6464
if kwds["tools"]:
65-
for (tool_path, tool_xml) in yield_tool_xmls(ctx, path):
65+
for (tool_path, tool_xml) in yield_tool_xmls(ctx, path,
66+
recursive=True):
6667
info("+Linting tool %s" % tool_path)
6768
lint_xml_with(
6869
lint_ctx,

planemo/tool_lint.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
import os
2-
import sys
3-
import traceback
42

53
from planemo.io import info
64
from planemo.io import error
75

86
import planemo.linters.xsd
97

10-
from galaxy.tools.loader_directory import load_tool_elements_from_path
8+
from planemo.tools import load_tool_elements_from_path
119
from galaxy.tools.lint import lint_xml
1210

1311
SKIP_XML_MESSAGE = "Skipping XML file - does not appear to be a tool %s."
1412
LINTING_TOOL_MESSAGE = "Linting tool %s"
1513
SHED_FILES = ["tool_dependencies.xml", "repository_dependencies.xml"]
1614

1715

18-
def lint_tools_on_path(ctx, path, lint_args, assert_tools=True):
16+
def lint_tools_on_path(ctx, path, lint_args, **kwds):
17+
assert_tools = kwds.get("assert_tools", True)
18+
recursive = kwds.get("recursive", False)
1919
exit = 0
2020
valid_tools = 0
21-
for (tool_path, tool_xml) in yield_tool_xmls(ctx, path):
21+
for (tool_path, tool_xml) in yield_tool_xmls(ctx, path, recursive):
2222
info("Linting tool %s" % tool_path)
2323
if not lint_xml(tool_xml, **lint_args):
2424
error("Failed linting")
@@ -30,8 +30,11 @@ def lint_tools_on_path(ctx, path, lint_args, assert_tools=True):
3030
return exit
3131

3232

33-
def yield_tool_xmls(ctx, path):
34-
tools = load_tool_elements_from_path(path, load_exception_handler)
33+
def yield_tool_xmls(ctx, path, recursive=False):
34+
tools = load_tool_elements_from_path(
35+
path,
36+
recursive,
37+
)
3538
for (tool_path, tool_xml) in tools:
3639
if not _is_tool_xml(ctx, tool_path, tool_xml):
3740
continue
@@ -57,11 +60,6 @@ def build_lint_args(ctx, **kwds):
5760
return lint_args
5861

5962

60-
def load_exception_handler(path, exc_info):
61-
error("Error loading tool with path %s" % path)
62-
traceback.print_exception(*exc_info, limit=1, file=sys.stderr)
63-
64-
6563
def _lint_extra_modules(**kwds):
6664
xsd = kwds.get("xsd", False)
6765
if xsd:

planemo/tools.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import sys
2+
import traceback
3+
from planemo.io import error
4+
5+
from galaxy.tools import loader_directory
6+
7+
8+
def load_tool_elements_from_path(path, recursive):
9+
return loader_directory.load_tool_elements_from_path(
10+
path,
11+
load_exception_handler,
12+
recursive,
13+
)
14+
15+
16+
def load_exception_handler(path, exc_info):
17+
error("Error loading tool with path %s" % path)
18+
traceback.print_exception(*exc_info, limit=1, file=sys.stderr)

planemo_ext/galaxy/tools/loader_directory.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fnmatch
12
import glob
23
import os
34
from ..tools import loader
@@ -8,16 +9,21 @@
89
log = logging.getLogger(__name__)
910

1011
PATH_DOES_NOT_EXIST_ERROR = "Could not load tools from path [%s] - this path does not exist."
12+
PATH_AND_RECURSIVE_ERROR = "Cannot specify a single file and recursive."
1113
LOAD_FAILURE_ERROR = "Failed to load tool with path %s."
1214

1315

1416
def load_exception_handler(path, exc_info):
1517
log.warn(LOAD_FAILURE_ERROR % path, exc_info=exc_info)
1618

1719

18-
def load_tool_elements_from_path(path, load_exception_handler=load_exception_handler):
20+
def load_tool_elements_from_path(
21+
path,
22+
load_exception_handler=load_exception_handler,
23+
recursive=False,
24+
):
1925
tool_elements = []
20-
for file in __find_tool_files(path):
26+
for file in __find_tool_files(path, recursive=recursive):
2127
try:
2228
looks_like_a_tool = __looks_like_a_tool(file)
2329
except IOError:
@@ -45,10 +51,30 @@ def __looks_like_a_tool(path):
4551
return False
4652

4753

48-
def __find_tool_files(path):
54+
def __find_tool_files(path, recursive):
55+
is_file = not os.path.isdir(path)
4956
if not os.path.exists(path):
5057
raise Exception(PATH_DOES_NOT_EXIST_ERROR)
51-
if not os.path.isdir(path):
58+
elif is_file and recursive:
59+
raise Exception(PATH_AND_RECURSIVE_ERROR)
60+
elif is_file:
5261
return [os.path.abspath(path)]
5362
else:
54-
return map(os.path.abspath, glob.glob(path + "/**.xml"))
63+
if not recursive:
64+
files = glob.glob(path + "/*.xml")
65+
else:
66+
files = _find_files(path, "*.xml")
67+
return map(os.path.abspath, files)
68+
69+
70+
def _find_files(directory, pattern='*'):
71+
if not os.path.exists(directory):
72+
raise ValueError("Directory not found {}".format(directory))
73+
74+
matches = []
75+
for root, dirnames, filenames in os.walk(directory):
76+
for filename in filenames:
77+
full_path = os.path.join(root, filename)
78+
if fnmatch.filter([full_path], pattern):
79+
matches.append(os.path.join(root, filename))
80+
return matches

tests/data/repos/multi_repos_nested/cat1/cat1.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</repeat>
1414
</inputs>
1515
<outputs>
16-
<data name="out_file1" format="input" metadata_source="input1"/>
16+
<data name="out_file1" format_source="input1" metadata_source="input1"/>
1717
</outputs>
1818
<tests>
1919
<test>
@@ -22,5 +22,6 @@
2222
</test>
2323
</tests>
2424
<help>
25+
Copy a dataset.
2526
</help>
2627
</tool>

tests/data/repos/multi_repos_nested/cat2/cat2.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</repeat>
1414
</inputs>
1515
<outputs>
16-
<data name="out_file1" format="input" metadata_source="input1"/>
16+
<data name="out_file1" format_source="input1" metadata_source="input1"/>
1717
</outputs>
1818
<tests>
1919
<test>
@@ -22,5 +22,6 @@
2222
</test>
2323
</tests>
2424
<help>
25+
Copy a dataset.
2526
</help>
2627
</tool>

tests/test_lint.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import os
22
import glob
33

4-
from .test_utils import CliTestCase
5-
from .test_utils import TEST_TOOLS_DIR
4+
from .test_utils import (
5+
CliTestCase,
6+
TEST_TOOLS_DIR,
7+
TEST_REPOS_DIR,
8+
)
69

710

811
class LintTestCase(CliTestCase):
@@ -30,3 +33,14 @@ def test_skips(self):
3033
# Check string splitting and stuff.
3134
lint_cmd = ["lint", "--skip", "xml_order, citations", fail_citation]
3235
self._check_exit_code(lint_cmd, exit_code=0)
36+
37+
def test_recursive(self):
38+
nested_dir = os.path.join(TEST_REPOS_DIR, "multi_repos_nested")
39+
40+
# Fails to find any tools without -r.
41+
lint_cmd = ["lint", "--skip", "citations", nested_dir]
42+
self._check_exit_code(lint_cmd, exit_code=2)
43+
44+
# Works with -r.
45+
lint_cmd = ["lint", "--skip", "citations", "-r", nested_dir]
46+
self._check_exit_code(lint_cmd, exit_code=0)

0 commit comments

Comments
 (0)