summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptmcg <ptmcg@austin.rr.com>2022-05-20 01:02:37 -0500
committerptmcg <ptmcg@austin.rr.com>2022-05-20 01:02:37 -0500
commit3a256cc444258ecc1321001702672c65eb5d425a (patch)
tree651c3d2eeb6d830d7e086dd88bc31bacfae0899d
parent79fe2b54bc08c791383ca81d4701b5afdd3d7390 (diff)
downloadpyparsing-git-3a256cc444258ecc1321001702672c65eb5d425a.tar.gz
Add embed argument to create_diagram, to suppress DOCTYPE, HEAD, and BODY tags
-rw-r--r--CHANGES8
-rw-r--r--pyparsing/core.py7
-rw-r--r--pyparsing/diagram/__init__.py12
-rw-r--r--tests/diag_embed.html61
-rw-r--r--tests/diag_no_embed.html71
-rw-r--r--tests/test_diagram.py41
6 files changed, 195 insertions, 5 deletions
diff --git a/CHANGES b/CHANGES
index 3074d6f..7c4cad7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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">&#91;combine&#93;</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">&#91;combine&#93;</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()