Skip to content

Commit

Permalink
Merge pull request #2080 from mhsmith/pyscript-2024.11.1
Browse files Browse the repository at this point in the history
Update to PyScript 2024.11.1
  • Loading branch information
mhsmith authored Dec 10, 2024
2 parents 5622e0e + 3455e9d commit 91e6caa
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 46 deletions.
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,
}

0 comments on commit 91e6caa

Please sign in to comment.