diff options
author | ptmcg <ptmcg@austin.rr.com> | 2022-05-20 01:02:37 -0500 |
---|---|---|
committer | ptmcg <ptmcg@austin.rr.com> | 2022-05-20 01:02:37 -0500 |
commit | 3a256cc444258ecc1321001702672c65eb5d425a (patch) | |
tree | 651c3d2eeb6d830d7e086dd88bc31bacfae0899d | |
parent | 79fe2b54bc08c791383ca81d4701b5afdd3d7390 (diff) | |
download | pyparsing-git-3a256cc444258ecc1321001702672c65eb5d425a.tar.gz |
Add embed argument to create_diagram, to suppress DOCTYPE, HEAD, and BODY tags
-rw-r--r-- | CHANGES | 8 | ||||
-rw-r--r-- | pyparsing/core.py | 7 | ||||
-rw-r--r-- | pyparsing/diagram/__init__.py | 12 | ||||
-rw-r--r-- | tests/diag_embed.html | 61 | ||||
-rw-r--r-- | tests/diag_no_embed.html | 71 | ||||
-rw-r--r-- | tests/test_diagram.py | 41 |
6 files changed, 195 insertions, 5 deletions
@@ -12,12 +12,20 @@ Version 3.0.10 - (in development) BEGIN, END = map(Keyword, "BEGIN END".split()) body_word = Word(alphas) expr = BEGIN + Group(body_word[:END]) + END + # equivalent to + # expr = BEGIN + Group(ZeroOrMore(body_word, stop_on=END)) + END print(expr.parse_string(test).as_list()) Prints: ['BEGIN', ['aaa', 'bbb', 'ccc'], 'END'] +- Added bool `embed` argument to `ParserElement.create_diagram()`. + When passed as True, the resulting diagram will omit the `<DOCTYPE>`, + `<HEAD>`, and `<BODY>` tags so that it can be embedded in other + HTML source. (Useful when embedding a call to `create_diagram()` in + a PyScript HTML page.) + - Fixed bug in srange, when parsing escaped '/' and '\' inside a range set. diff --git a/pyparsing/core.py b/pyparsing/core.py index a806f5b..fb9d594 100644 --- a/pyparsing/core.py +++ b/pyparsing/core.py @@ -2170,6 +2170,7 @@ class ParserElement(ABC): vertical: int = 3, show_results_names: bool = False, show_groups: bool = False, + embed: bool = False, **kwargs, ) -> None: """ @@ -2183,6 +2184,8 @@ class ParserElement(ABC): - show_results_names - bool flag whether diagram should show annotations for defined results names - show_groups - bool flag whether groups should be highlighted with an unlabeled surrounding box + - embed - bool flag whether generated HTML should omit <HEAD>, <BODY>, and <DOCTYPE> tags to embed + the resulting HTML in an enclosing HTML source Additional diagram-formatting keyword arguments can also be included; see railroad.Diagram class. """ @@ -2205,10 +2208,10 @@ class ParserElement(ABC): ) if isinstance(output_html, (str, Path)): with open(output_html, "w", encoding="utf-8") as diag_file: - diag_file.write(railroad_to_html(railroad)) + diag_file.write(railroad_to_html(railroad, embed=embed)) else: # we were passed a file-like object, just write to it - output_html.write(railroad_to_html(railroad)) + output_html.write(railroad_to_html(railroad, embed=embed)) setDefaultWhitespaceChars = set_default_whitespace_chars inlineLiteralsUsing = inline_literals_using diff --git a/pyparsing/diagram/__init__.py b/pyparsing/diagram/__init__.py index 8986447..25f10e9 100644 --- a/pyparsing/diagram/__init__.py +++ b/pyparsing/diagram/__init__.py @@ -17,11 +17,13 @@ import inspect jinja2_template_source = """\ +{% if not embed %} <!DOCTYPE html> <html> <head> +{% endif %} {% if not head %} - <style type="text/css"> + <style> .railroad-heading { font-family: monospace; } @@ -29,8 +31,10 @@ jinja2_template_source = """\ {% else %} {{ head | safe }} {% endif %} +{% if not embed %} </head> <body> +{% endif %} {{ body | safe }} {% for diagram in diagrams %} <div class="railroad-group"> @@ -41,8 +45,10 @@ jinja2_template_source = """\ </div> </div> {% endfor %} +{% if not embed %} </body> </html> +{% endif %} """ template = Template(jinja2_template_source) @@ -127,7 +133,7 @@ class EditablePartial(Generic[T]): return self.func(*args, **kwargs) -def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str: +def railroad_to_html(diagrams: List[NamedDiagram], embed=False, **kwargs) -> str: """ Given a list of NamedDiagram, produce a single HTML string that visualises those diagrams :params kwargs: kwargs to be passed in to the template @@ -143,7 +149,7 @@ def railroad_to_html(diagrams: List[NamedDiagram], **kwargs) -> str: title += " (root)" data.append({"title": title, "text": "", "svg": io.getvalue()}) - return template.render(diagrams=data, **kwargs) + return template.render(diagrams=data, embed=embed, **kwargs) def resolve_partial(partial: "EditablePartial[T]") -> T: diff --git a/tests/diag_embed.html b/tests/diag_embed.html new file mode 100644 index 0000000..1ef1b1e --- /dev/null +++ b/tests/diag_embed.html @@ -0,0 +1,61 @@ + + + <style> + .railroad-heading { + font-family: monospace; + } + </style> + + + + + <div class="railroad-group"> + <h1 class="railroad-heading"></h1> + <div class="railroad-description"></div> + <div class="railroad-svg"> + <svg class="railroad-diagram" height="94" viewBox="0 0 529.5 94" width="529.5" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g transform="translate(.5 .5)"> +<style>/* <![CDATA[ */ + svg.railroad-diagram { + background-color:hsl(30,20%,95%); + } + svg.railroad-diagram path { + stroke-width:3; + stroke:black; + fill:rgba(0,0,0,0); + } + svg.railroad-diagram text { + font:bold 14px monospace; + text-anchor:middle; + } + svg.railroad-diagram text.label{ + text-anchor:start; + } + svg.railroad-diagram text.comment{ + font:italic 12px monospace; + } + svg.railroad-diagram rect{ + stroke-width:3; + stroke:black; + fill:hsl(120,100%,90%); + } + svg.railroad-diagram rect.group-box { + stroke: gray; + stroke-dasharray: 10 5; + fill: none; + } + +/* ]]> */ +</style><g> +<path d="M20 45v20m10 -20v20m-10 -10h20"></path></g><path d="M40 55h10"></path><g> +<path d="M50 55h0.0"></path><path d="M479.5 55h0.0"></path><rect class="group-box" height="38" rx="10" ry="10" width="429.5" x="50.0" y="36"></rect><g> +<path d="M50.0 55h10.0"></path><path d="M469.5 55h10.0"></path><g class="terminal "> +<path d="M60.0 55h0.0"></path><path d="M139.5 55h0.0"></path><rect height="22" rx="10" ry="10" width="79.5" x="60.0" y="44"></rect><text x="99.75" y="59">W:(0-9)</text></g><path d="M139.5 55h10"></path><path d="M149.5 55h10"></path><g class="terminal "> +<path d="M159.5 55h0.0"></path><path d="M205.0 55h0.0"></path><rect height="22" rx="10" ry="10" width="45.5" x="159.5" y="44"></rect><text x="182.25" y="59">':'</text></g><path d="M205.0 55h10"></path><path d="M215.0 55h10"></path><g class="terminal "> +<path d="M225.0 55h0.0"></path><path d="M304.5 55h0.0"></path><rect height="22" rx="10" ry="10" width="79.5" x="225.0" y="44"></rect><text x="264.75" y="59">W:(0-9)</text></g><path d="M304.5 55h10"></path><path d="M314.5 55h10"></path><g class="terminal "> +<path d="M324.5 55h0.0"></path><path d="M370.0 55h0.0"></path><rect height="22" rx="10" ry="10" width="45.5" x="324.5" y="44"></rect><text x="347.25" y="59">':'</text></g><path d="M370.0 55h10"></path><path d="M380.0 55h10"></path><g class="terminal "> +<path d="M390.0 55h0.0"></path><path d="M469.5 55h0.0"></path><rect height="22" rx="10" ry="10" width="79.5" x="390.0" y="44"></rect><text x="429.75" y="59">W:(0-9)</text></g></g><g class="non-terminal "> +<path d="M50.0 28h0.0"></path><path d="M123.0 28h0.0"></path><text class="comment" x="86.5" y="33">[combine]</text></g></g><path d="M479.5 55h10"></path><path d="M 489.5 55 h 20 m -10 -10 v 20 m 10 -20 v 20"></path></g></svg> + </div> + </div> + diff --git a/tests/diag_no_embed.html b/tests/diag_no_embed.html new file mode 100644 index 0000000..e0fdd5a --- /dev/null +++ b/tests/diag_no_embed.html @@ -0,0 +1,71 @@ + +<!DOCTYPE html> +<html> +<head> + + + <style> + .railroad-heading { + font-family: monospace; + } + </style> + + +</head> +<body> + + + + <div class="railroad-group"> + <h1 class="railroad-heading"></h1> + <div class="railroad-description"></div> + <div class="railroad-svg"> + <svg class="railroad-diagram" height="94" viewBox="0 0 529.5 94" width="529.5" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<g transform="translate(.5 .5)"> +<style>/* <![CDATA[ */ + svg.railroad-diagram { + background-color:hsl(30,20%,95%); + } + svg.railroad-diagram path { + stroke-width:3; + stroke:black; + fill:rgba(0,0,0,0); + } + svg.railroad-diagram text { + font:bold 14px monospace; + text-anchor:middle; + } + svg.railroad-diagram text.label{ + text-anchor:start; + } + svg.railroad-diagram text.comment{ + font:italic 12px monospace; + } + svg.railroad-diagram rect{ + stroke-width:3; + stroke:black; + fill:hsl(120,100%,90%); + } + svg.railroad-diagram rect.group-box { + stroke: gray; + stroke-dasharray: 10 5; + fill: none; + } + +/* ]]> */ +</style><g> +<path d="M20 45v20m10 -20v20m-10 -10h20"></path></g><path d="M40 55h10"></path><g> +<path d="M50 55h0.0"></path><path d="M479.5 55h0.0"></path><rect class="group-box" height="38" rx="10" ry="10" width="429.5" x="50.0" y="36"></rect><g> +<path d="M50.0 55h10.0"></path><path d="M469.5 55h10.0"></path><g class="terminal "> +<path d="M60.0 55h0.0"></path><path d="M139.5 55h0.0"></path><rect height="22" rx="10" ry="10" width="79.5" x="60.0" y="44"></rect><text x="99.75" y="59">W:(0-9)</text></g><path d="M139.5 55h10"></path><path d="M149.5 55h10"></path><g class="terminal "> +<path d="M159.5 55h0.0"></path><path d="M205.0 55h0.0"></path><rect height="22" rx="10" ry="10" width="45.5" x="159.5" y="44"></rect><text x="182.25" y="59">':'</text></g><path d="M205.0 55h10"></path><path d="M215.0 55h10"></path><g class="terminal "> +<path d="M225.0 55h0.0"></path><path d="M304.5 55h0.0"></path><rect height="22" rx="10" ry="10" width="79.5" x="225.0" y="44"></rect><text x="264.75" y="59">W:(0-9)</text></g><path d="M304.5 55h10"></path><path d="M314.5 55h10"></path><g class="terminal "> +<path d="M324.5 55h0.0"></path><path d="M370.0 55h0.0"></path><rect height="22" rx="10" ry="10" width="45.5" x="324.5" y="44"></rect><text x="347.25" y="59">':'</text></g><path d="M370.0 55h10"></path><path d="M380.0 55h10"></path><g class="terminal "> +<path d="M390.0 55h0.0"></path><path d="M469.5 55h0.0"></path><rect height="22" rx="10" ry="10" width="79.5" x="390.0" y="44"></rect><text x="429.75" y="59">W:(0-9)</text></g></g><g class="non-terminal "> +<path d="M50.0 28h0.0"></path><path d="M123.0 28h0.0"></path><text class="comment" x="86.5" y="33">[combine]</text></g></g><path d="M479.5 55h10"></path><path d="M 489.5 55 h 20 m -10 -10 v 20 m 10 -20 v 20"></path></g></svg> + </div> + </div> + + +</body> +</html> diff --git a/tests/test_diagram.py b/tests/test_diagram.py index eeef20e..d1df67a 100644 --- a/tests/test_diagram.py +++ b/tests/test_diagram.py @@ -1,4 +1,6 @@ import unittest +from io import StringIO +from pathlib import Path from typing import List from examples.jsonParser import jsonObject @@ -12,6 +14,9 @@ import os import sys +curdir = Path(__file__).parent + + class TestRailroadDiagrams(unittest.TestCase): def railroad_debug(self) -> bool: """ @@ -142,3 +147,39 @@ class TestRailroadDiagrams(unittest.TestCase): assert len(railroad) == 1 railroad = to_railroad(grammar, show_results_names=True) assert len(railroad) == 1 + + def test_create_diagram(self): + ints = pp.Word(pp.nums) + grammar = pp.Combine( + ints("hours") + + pp.Literal(":") + + ints("minutes") + + pp.Literal(":") + + ints("seconds") + ) + + diag_strio = StringIO() + grammar.create_diagram(output_html=diag_strio) + diag_str = diag_strio.getvalue() + expected = (curdir / "diag_no_embed.html").read_text() + assert diag_str == expected + + def test_create_diagram_embed(self): + ints = pp.Word(pp.nums) + grammar = pp.Combine( + ints("hours") + + pp.Literal(":") + + ints("minutes") + + pp.Literal(":") + + ints("seconds") + ) + + diag_strio = StringIO() + grammar.create_diagram(output_html=diag_strio, embed=True) + diag_str = diag_strio.getvalue() + expected = (curdir / "diag_embed.html").read_text() + assert diag_str == expected + + +if __name__ == "__main__": + unittest.main() |