Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to PyScript 2024.11.1 #2080

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/2080.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The web template now targets PyScript version 2024.11.1. In addition, the web template can provide a base ``pyscript.toml`` that Briefcase will update as required during the build process.
60 changes: 34 additions & 26 deletions src/briefcase/platforms/web/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
class StaticWebMixin:
output_format = "static"
platform = "web"
platform_target_version = "0.3.21"

def project_path(self, app):
return self.bundle_path(app) / "www"
Expand Down Expand Up @@ -180,33 +181,40 @@ def build_app(self, app: AppConfig, **kwargs):
) from e

with self.input.wait_bar("Writing Pyscript configuration file..."):
# Load any pre-existing pyscript.toml provided by the template. If the file
# doesn't exist, assume an empty pyscript.toml as a starting point.
try:
with (self.project_path(app) / "pyscript.toml").open("rb") as f:
config = tomllib.load(f)
except tomllib.TOMLDecodeError as e:
raise BriefcaseConfigError(
f"pyscript.toml content isn't valid TOML: {e}"
) from e
except FileNotFoundError:
config = {}

# Add the packages declaration to the existing pyscript.toml.
# Ensure that we're using Unix path separators, as the content
# will be parsed by pyscript in the browser.
config["packages"] = [
f'/{"/".join(wheel.relative_to(self.project_path(app)).parts)}'
for wheel in sorted(self.wheel_path(app).glob("*.whl"))
]

# Parse any additional pyscript.toml content, and merge it into
# the overall content
try:
extra = tomllib.loads(app.extra_pyscript_toml_content)
config.update(extra)
except tomllib.TOMLDecodeError as e:
raise BriefcaseConfigError(
f"Extra pyscript.toml content isn't valid TOML: {e}"
) from e
except AttributeError:
pass

# Write the final configuration.
with (self.project_path(app) / "pyscript.toml").open("wb") as f:
config = {
"name": app.formal_name,
"description": app.description,
"version": app.version,
"splashscreen": {"autoclose": True},
"terminal": False,
# Ensure that we're using Unix path separators, as the content
# will be parsed by pyscript in the browser.
"packages": [
f'/{"/".join(wheel.relative_to(self.project_path(app)).parts)}'
for wheel in sorted(self.wheel_path(app).glob("*.whl"))
],
}
# Parse any additional pyscript.toml content, and merge it into
# the overall content
try:
extra = tomllib.loads(app.extra_pyscript_toml_content)
config.update(extra)
except tomllib.TOMLDecodeError as e:
raise BriefcaseConfigError(
f"Extra pyscript.toml content isn't valid TOML: {e}"
) from e
except AttributeError:
pass

# Write the final configuration.
tomli_w.dump(config, f)

self.logger.info("Compile static web content from wheels")
Expand Down
9 changes: 9 additions & 0 deletions tests/platforms/web/static/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ def first_app_generated(first_app_config, tmp_path):
# Create index.html
create_file(bundle_path / "www/index.html", "<html></html>")

# Create the initial pyscript.toml
create_file(
bundle_path / "www/pyscript.toml",
"""
existing-key-1 = "value-1"
existing-key-2 = 2
""",
)

# Create the initial briefcase.css
create_file(
bundle_path / "www/static/css/briefcase.css",
Expand Down
90 changes: 70 additions & 20 deletions tests/platforms/web/static/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from briefcase.integrations.subprocess import Subprocess
from briefcase.platforms.web.static import StaticWebBuildCommand

from ....utils import create_wheel
from ....utils import create_file, create_wheel


@pytest.fixture
Expand Down Expand Up @@ -124,11 +124,8 @@ def mock_run(*args, **kwargs):
# Pyscript.toml has been written
with (bundle_path / "www/pyscript.toml").open("rb") as f:
assert tomllib.load(f) == {
"name": "First App",
"description": "The first simple app \\ demonstration",
"version": "0.0.1",
"splashscreen": {"autoclose": True},
"terminal": False,
"existing-key-1": "value-1",
"existing-key-2": 2,
"packages": [
"/static/wheels/dependency-1.2.3-py3-none-any.whl",
"/static/wheels/first_app-1.2.3-py3-none-any.whl",
Expand Down Expand Up @@ -205,20 +202,68 @@ def test_build_app_custom_pyscript_toml(build_command, first_app_generated, tmp_
# Pyscript.toml has been written
with (bundle_path / "www/pyscript.toml").open("rb") as f:
assert tomllib.load(f) == {
"name": "First App",
"description": "The first simple app \\ demonstration",
"version": "0.0.1",
"existing-key-1": "value-1",
"existing-key-2": 2,
"something": "custom",
"splashscreen": {"wiggle": False},
"terminal": False,
"packages": ["something-custom"],
"runtimes": [
{"src": "https://example.com/pyodide.js"},
],
}


def test_build_app_invalid_custom_pyscript_toml(
def test_build_app_no_template_pyscript_toml(
build_command, first_app_generated, tmp_path
):
"""An app whose template doesn't provide pyscript.toml gets a basic config."""
# Remove the templated pyscript.toml
bundle_path = tmp_path / "base_path/build/first-app/web/static"
(bundle_path / "www/pyscript.toml").unlink()

# Mock the side effect of invoking shutil
build_command.tools.shutil.rmtree.side_effect = lambda *args: shutil.rmtree(
bundle_path / "www/static/wheels"
)

# Build the web app.
build_command.build_app(first_app_generated)

# Pyscript.toml has been written with only the packages content
with (bundle_path / "www/pyscript.toml").open("rb") as f:
assert tomllib.load(f) == {
"packages": [],
}


def test_build_app_invalid_template_pyscript_toml(
build_command, first_app_generated, tmp_path
):
"""An app with an invalid pyscript.toml raises an error."""
# Re-write an invalid templated pyscript.toml
bundle_path = tmp_path / "base_path/build/first-app/web/static"
(bundle_path / "www/pyscript.toml").unlink()
create_file(
bundle_path / "www/pyscript.toml",
"""
This is not valid toml.
""",
)

# Mock the side effect of invoking shutil
build_command.tools.shutil.rmtree.side_effect = lambda *args: shutil.rmtree(
bundle_path / "www/static/wheels"
)

# Building the web app raises an error
with pytest.raises(
BriefcaseConfigError,
match=r"Briefcase configuration error: pyscript.toml content isn't valid TOML: Expected",
):
build_command.build_app(first_app_generated)


def test_build_app_invalid_extra_pyscript_toml_content(
build_command, first_app_generated, tmp_path
):
"""An app with invalid extra pyscript.toml content raises an error."""
Expand Down Expand Up @@ -374,11 +419,8 @@ def mock_run(*args, **kwargs):
# Pyscript.toml has been written
with (bundle_path / "www/pyscript.toml").open("rb") as f:
assert tomllib.load(f) == {
"name": "First App",
"description": "The first simple app \\ demonstration",
"version": "0.0.1",
"splashscreen": {"autoclose": True},
"terminal": False,
"existing-key-1": "value-1",
"existing-key-2": 2,
"packages": [
"/static/wheels/first_app-1.2.3-py3-none-any.whl",
],
Expand Down Expand Up @@ -458,8 +500,12 @@ def test_app_package_fail(build_command, first_app_generated, tmp_path):
# Wheels folder still exists
assert (bundle_path / "www/static/wheels").is_dir()

# Pyscript.toml was not written
assert not (bundle_path / "www/pyscript.toml").exists()
# Pyscript.toml content has not changed
with (bundle_path / "www/pyscript.toml").open("rb") as f:
assert tomllib.load(f) == {
"existing-key-1": "value-1",
"existing-key-2": 2,
}


def test_dependency_fail(build_command, first_app_generated, tmp_path):
Expand Down Expand Up @@ -530,5 +576,9 @@ def test_dependency_fail(build_command, first_app_generated, tmp_path):
# Wheels folder still exists
assert (bundle_path / "www/static/wheels").is_dir()

# Pyscript.toml was not written
assert not (bundle_path / "www/pyscript.toml").exists()
# Pyscript.toml content has not changed
with (bundle_path / "www/pyscript.toml").open("rb") as f:
assert tomllib.load(f) == {
"existing-key-1": "value-1",
"existing-key-2": 2,
}
Loading