Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/gxformat2/markdown_parse.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
author | shellac |
---|---|
date | Thu, 14 May 2020 14:56:58 -0400 |
parents | 26e78fe6e8c4 |
children |
comparison
equal
deleted
inserted
replaced
1:75ca89e9b81c | 2:6af9afd405e9 |
---|---|
1 """Utilities for parsing "Galaxy Flavored Markdown". | |
2 | |
3 See markdown_util.py for loading objects and interacting with the rest of Galaxy. | |
4 This file is meant to be relatively self contained and just used to "parse" and validate | |
5 Galaxy Markdown. Keeping things isolated to allow re-use of these utilities in other | |
6 projects (e.g. gxformat2). | |
7 """ | |
8 import re | |
9 | |
10 BLOCK_FENCE_START = re.compile(r'```.*') | |
11 BLOCK_FENCE_END = re.compile(r'```[\s]*') | |
12 GALAXY_FLAVORED_MARKDOWN_CONTAINER_LINE_PATTERN = re.compile( | |
13 r"```\s*galaxy\s*" | |
14 ) | |
15 VALID_CONTAINER_END_PATTERN = re.compile(r"^```\s*$") | |
16 GALAXY_FLAVORED_MARKDOWN_CONTAINERS = [ | |
17 "history_dataset_display", | |
18 "history_dataset_collection_display", | |
19 "history_dataset_as_image", | |
20 "history_dataset_peek", | |
21 "history_dataset_info", | |
22 "workflow_display", | |
23 "job_metrics", | |
24 "job_parameters", | |
25 "tool_stderr", | |
26 "tool_stdout", | |
27 ] | |
28 INVOCATION_SECTIONS = [ | |
29 "invocation_inputs", | |
30 "invocation_outputs", | |
31 ] | |
32 ALL_CONTAINER_TYPES = GALAXY_FLAVORED_MARKDOWN_CONTAINERS + INVOCATION_SECTIONS | |
33 GALAXY_FLAVORED_MARKDOWN_CONTAINER_REGEX = "(%s)" % "|".join(ALL_CONTAINER_TYPES) | |
34 | |
35 ARG_VAL_REGEX = r'''[\w_\-]+|\"[^\"]+\"|\'[^\']+\'''' | |
36 FUNCTION_ARG = r'\s*\w+\s*=\s*(?:%s)\s*' % ARG_VAL_REGEX | |
37 FUNCTION_CALL_LINE_TEMPLATE = r'\s*%s\s*\((?:' + FUNCTION_ARG + r')?\)\s*' | |
38 GALAXY_MARKDOWN_FUNCTION_CALL_LINE = re.compile(FUNCTION_CALL_LINE_TEMPLATE % GALAXY_FLAVORED_MARKDOWN_CONTAINER_REGEX) | |
39 WHITE_SPACE_ONLY_PATTERN = re.compile(r"^[\s]+$") | |
40 | |
41 | |
42 def validate_galaxy_markdown(galaxy_markdown, internal=True): | |
43 """Validate the supplied markdown and throw an ValueError with reason if invalid.""" | |
44 expecting_container_close_for = None | |
45 last_line_no = 0 | |
46 function_calls = 0 | |
47 for (line, fenced, open_fence, line_no) in _split_markdown_lines(galaxy_markdown): | |
48 last_line_no = line_no | |
49 | |
50 def invalid_line(template, **kwd): | |
51 if "line" in kwd: | |
52 kwd["line"] = line.rstrip("\r\n") | |
53 raise ValueError("Invalid line %d: %s" % (line_no + 1, template.format(**kwd))) | |
54 | |
55 expecting_container_close = expecting_container_close_for is not None | |
56 if not fenced and expecting_container_close: | |
57 invalid_line("[{line}] is not expected close line for [{expected_for}]", line=line, expected_for=expecting_container_close_for) | |
58 continue | |
59 elif not fenced: | |
60 continue | |
61 elif fenced and expecting_container_close and BLOCK_FENCE_END.match(line): | |
62 # reset | |
63 expecting_container_close_for = None | |
64 function_calls = 0 | |
65 elif open_fence and GALAXY_FLAVORED_MARKDOWN_CONTAINER_LINE_PATTERN.match(line): | |
66 if expecting_container_close: | |
67 if not VALID_CONTAINER_END_PATTERN.match(line): | |
68 invalid_line("Invalid command close line [{line}] for [{expected_for}]", line=line, expected_for=expecting_container_close_for) | |
69 # else closing container and we're done | |
70 expecting_container_close_for = None | |
71 function_calls = 0 | |
72 continue | |
73 | |
74 expecting_container_close_for = line | |
75 continue | |
76 elif fenced and line and expecting_container_close_for: | |
77 if GALAXY_MARKDOWN_FUNCTION_CALL_LINE.match(line): | |
78 function_calls += 1 | |
79 if function_calls > 1: | |
80 invalid_line("Only one Galaxy directive is allowed per fenced Galaxy block (```galaxy)") | |
81 continue | |
82 else: | |
83 invalid_line("Invalid embedded Galaxy markup line [{line}]", line=line) | |
84 | |
85 # Markdown unrelated to Galaxy object containers. | |
86 continue | |
87 | |
88 if expecting_container_close_for: | |
89 template = "Invalid line %d: %s" | |
90 msg = template % (last_line_no, "close of block for [{expected_for}] expected".format(expected_for=expecting_container_close_for)) | |
91 raise ValueError(msg) | |
92 | |
93 | |
94 def _split_markdown_lines(markdown): | |
95 """Yield lines of a markdown document line-by-line keeping track of fencing. | |
96 | |
97 'Fenced' lines are code-like block (e.g. between ```) that shouldn't contain | |
98 Markdown markup. | |
99 """ | |
100 block_fenced = False | |
101 indent_fenced = False | |
102 for line_number, line in enumerate(markdown.splitlines(True)): | |
103 open_fence_this_iteration = False | |
104 indent_fenced = line.startswith(" ") or (indent_fenced and WHITE_SPACE_ONLY_PATTERN.match(line)) | |
105 if not block_fenced: | |
106 if BLOCK_FENCE_START.match(line): | |
107 open_fence_this_iteration = True | |
108 block_fenced = True | |
109 yield (line, block_fenced or indent_fenced, open_fence_this_iteration, line_number) | |
110 if not open_fence_this_iteration and BLOCK_FENCE_END.match(line): | |
111 block_fenced = False | |
112 | |
113 | |
114 __all__ = ( | |
115 'validate_galaxy_markdown', | |
116 'GALAXY_MARKDOWN_FUNCTION_CALL_LINE', | |
117 ) |