Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/gxformat2/markdown_parse.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 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 ) |
