More plugins: splashscreen and importmap (#938)

This PR move codes from main.ts into two new plugins:

- splashscreen (formerly known as py-loader)
- importmap

The old setting config.autoclose_loader is still supported but deprecated; the new setting is config.splashscreen.autoclose.

Moreover, it does a small refactoring around UserError: now UserErrors are correctly caught even if they are raised from within afterRuntimeLoad.
This commit is contained in:
Antonio Cuni
2022-11-16 18:08:17 +01:00
committed by GitHub
parent b79ceea7a8
commit 41ebaaf366
19 changed files with 498 additions and 284 deletions

View File

@@ -77,6 +77,7 @@ class PyScriptTest:
# fixture, the server automatically starts in its own thread.
self.http_server = request.getfixturevalue("http_server")
self.router = None
self.is_fake_server = False
else:
# use the internal playwright routing
self.http_server = "http://fake_server"
@@ -87,6 +88,7 @@ class PyScriptTest:
usepdb=request.config.option.usepdb,
)
self.router.install(page)
self.is_fake_server = True
#
self.init_page(page)
#

View File

@@ -0,0 +1,65 @@
from .support import PyScriptTest
class TestImportmap(PyScriptTest):
def test_importmap(self):
src = """
export function say_hello(who) {
console.log("hello from", who);
}
"""
self.writefile("mymod.js", src)
#
self.pyscript_run(
"""
<script type="importmap">
{
"imports": {
"mymod": "/mymod.js"
}
}
</script>
<script type="module">
import { say_hello } from "mymod";
say_hello("JS");
</script>
<py-script>
import mymod
mymod.say_hello("Python")
</py-script>
"""
)
assert self.console.log.lines == [
"hello from JS",
self.PY_COMPLETE,
"hello from Python",
]
def test_invalid_json(self):
self.pyscript_run(
"""
<script type="importmap">
this is not valid JSON
</script>
<py-script>
print("hello world")
</py-script>
""",
wait_for_pyscript=False,
)
# this error is raised by the browser itself, when *it* tries to parse
# the import map
self.check_js_errors("Failed to parse import map")
self.wait_for_pyscript()
assert self.console.log.lines == [
self.PY_COMPLETE,
"hello world",
]
# this warning is shown by pyscript, when *we* try to parse the import
# map
banner = self.page.locator(".py-warning")
assert "Failed to parse import map" in banner.inner_text()

View File

@@ -5,7 +5,7 @@ import tempfile
import pytest
import requests
from .support import JsErrors, PyScriptTest
from .support import PyScriptTest
URL = "https://github.com/pyodide/pyodide/releases/download/0.20.0/pyodide-build-0.20.0.tar.bz2"
TAR_NAME = "pyodide-build-0.20.0.tar.bz2"
@@ -245,30 +245,20 @@ class TestConfig(PyScriptTest):
wait_for_pyscript=False,
)
# This is expected if running pytest with --dev flag
localErrorContent = """PyScript: Access to local files
if self.is_fake_server:
expected = """PyScript: Access to local files
(using "Paths:" in &lt;py-config&gt;)
is not available when directly opening a HTML file;
you must use a webserver to serve the additional files."""
# This is expected if running a live server
serverErrorContent = (
"Loading from file <u>./f.py</u> failed with error 404 (File not Found). "
"Are your filename and path are correct?"
)
else:
expected = (
"Loading from file <u>./f.py</u> failed with error 404 (File not Found). "
"Are your filename and path are correct?"
)
inner_html = self.page.locator(".py-error").inner_html()
assert localErrorContent in inner_html or serverErrorContent in inner_html
assert "Failed to load resource" in self.console.error.lines[0]
assert "Caught an error in fetchPaths" in self.console.warning.lines[0]
with pytest.raises(JsErrors) as exc:
self.check_js_errors()
received_error_msg = str(exc.value)
assert (
localErrorContent in received_error_msg
or serverErrorContent in received_error_msg
)
assert expected in inner_html
assert expected in self.console.error.lines[-1]
def test_paths_from_packages(self):
self.writefile("utils/__init__.py", "")

View File

@@ -0,0 +1,86 @@
from playwright.sync_api import expect
from .support import PyScriptTest
class TestSplashscreen(PyScriptTest):
def test_autoshow_and_autoclose(self):
"""
By default, we show the splashscreen and we close it when the loading is
complete.
XXX: this test is a bit fragile: now it works reliably because the
startup is so slow that when we do expect(div).to_be_visible(), the
splashscreen is still there. But in theory, if the startup become very
fast, it could happen that by the time we arrive in python lang, it
has already been removed.
"""
self.pyscript_run(
"""
<py-script>
print('hello pyscript')
</py-script>
""",
wait_for_pyscript=False,
)
div = self.page.locator("py-splashscreen > div")
expect(div).to_be_visible()
expect(div).to_contain_text("Python startup...")
assert "Python startup..." in self.console.info.text
#
# now we wait for the startup to complete
self.wait_for_pyscript()
#
# and now the splashscreen should have been removed
expect(div).to_be_hidden()
assert self.page.locator("py-locator").count() == 0
#
assert self.console.log.lines == [
self.PY_COMPLETE,
"hello pyscript",
]
def test_autoclose_false(self):
self.pyscript_run(
"""
<py-config>
[splashscreen]
autoclose = false
</py-config>
<py-script>
print('hello pyscript')
</py-script>
""",
)
div = self.page.locator("py-splashscreen > div")
expect(div).to_be_visible()
expect(div).to_contain_text("Python startup...")
expect(div).to_contain_text("Startup complete")
assert self.console.log.lines == [
self.PY_COMPLETE,
"hello pyscript",
]
def test_autoclose_loader_deprecated(self):
self.pyscript_run(
"""
<py-config>
autoclose_loader = false
</py-config>
<py-script>
print('hello pyscript')
</py-script>
""",
)
warning = self.page.locator(".py-warning")
inner_text = warning.inner_text()
assert "The setting autoclose_loader is deprecated" in inner_text
#
div = self.page.locator("py-splashscreen > div")
expect(div).to_be_visible()
expect(div).to_contain_text("Python startup...")
expect(div).to_contain_text("Startup complete")
assert self.console.log.lines == [
self.PY_COMPLETE,
"hello pyscript",
]