diff --git a/.github/workflows/dashboard.yaml b/.github/workflows/dashboard.yaml
deleted file mode 100644
index ee47b479..00000000
--- a/.github/workflows/dashboard.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-name: Push issue to Github Project dashboard
-
-on:
- issues:
- types:
- - opened
- pull_request_target:
- types:
- - opened
-
-jobs:
- add_to_project:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/add-to-project@v0.0.3
- with:
- project-url: https://github.com/orgs/pyscript/projects/4/
- github-token: ${{ secrets.PROJECT_TOKEN }}
diff --git a/pyscriptjs/src/python/pyscript.py b/pyscriptjs/src/python/pyscript.py
index f8999b4e..816082a4 100644
--- a/pyscriptjs/src/python/pyscript.py
+++ b/pyscriptjs/src/python/pyscript.py
@@ -1,5 +1,6 @@
import asyncio
import base64
+import html
import io
import time
from textwrap import dedent
@@ -35,7 +36,7 @@ def identity(value, meta):
MIME_RENDERERS = {
- "text/plain": identity,
+ "text/plain": html.escape,
"text/html": identity,
"image/png": lambda value, meta: render_image("image/png", value, meta),
"image/jpeg": lambda value, meta: render_image("image/jpeg", value, meta),
@@ -45,6 +46,18 @@ MIME_RENDERERS = {
}
+class HTML:
+ """
+ Wrap a string so that display() can render it as plain HTML
+ """
+
+ def __init__(self, html):
+ self._html = html
+
+ def _repr_html_(self):
+ return self._html
+
+
def eval_formatter(obj, print_method):
"""
Evaluates a formatter method.
@@ -68,7 +81,7 @@ def format_mime(obj):
Formats object using _repr_x_ methods.
"""
if isinstance(obj, str):
- return obj, "text/plain"
+ return html.escape(obj), "text/plain"
mimebundle = eval_formatter(obj, "_repr_mimebundle_")
if isinstance(mimebundle, tuple):
diff --git a/pyscriptjs/tests/integration/test_02_output.py b/pyscriptjs/tests/integration/test_02_output.py
index ef7372b3..0605677d 100644
--- a/pyscriptjs/tests/integration/test_02_output.py
+++ b/pyscriptjs/tests/integration/test_02_output.py
@@ -1,3 +1,4 @@
+import html
import re
import pytest
@@ -201,6 +202,30 @@ class TestOutput(PyScriptTest):
== "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')"
)
+ def test_display_should_escape(self):
+ self.pyscript_run(
+ """
+ hello world
hello world
") + assert out.inner_text() == "hello world
" + + def test_display_HTML(self): + self.pyscript_run( + """ +hello world
")) +hello world
" + assert out.inner_text() == "hello world" + def test_image_display(self): self.pyscript_run( """ diff --git a/pyscriptjs/tests/py-unit/test_pyscript.py b/pyscriptjs/tests/py-unit/test_pyscript.py index fec923b5..a7b7c09d 100644 --- a/pyscriptjs/tests/py-unit/test_pyscript.py +++ b/pyscriptjs/tests/py-unit/test_pyscript.py @@ -1,3 +1,4 @@ +import sys from unittest.mock import Mock import pyscript @@ -24,7 +25,26 @@ class TestElement: def test_format_mime_str(): obj = "just a string" + out, mime = pyscript.format_mime(obj) + assert out == obj + assert mime == "text/plain" - res = pyscript.format_mime(obj) - assert res[0] == obj - assert res[1] == "text/plain" + +def test_format_mime_str_escaping(): + obj = "hello
" + out, mime = pyscript.format_mime(obj) + assert out == "<p>hello</p>" + assert mime == "text/plain" + + +def test_format_mime_repr_escaping(): + out, mime = pyscript.format_mime(sys) + assert out == "<module 'sys' (built-in)>" + assert mime == "text/plain" + + +def test_format_mime_HTML(): + obj = pyscript.HTML("hello
") + out, mime = pyscript.format_mime(obj) + assert out == "hello
" + assert mime == "text/html"