Skip to content

Commit

Permalink
separate bundle creation from URL encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
gadenbuie committed Jan 6, 2024
1 parent 6d5c22a commit 373f639
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 40 deletions.
11 changes: 9 additions & 2 deletions shinylive/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
"""A package for packaging Shiny applications that run on Python in the browser."""

from . import _version
from ._url import decode_shinylive_url, encode_shinylive_url
from ._url import (
create_shinylive_bundle_file,
create_shinylive_bundle_text,
create_shinylive_url,
decode_shinylive_url,
)

__version__ = _version.SHINYLIVE_PACKAGE_VERSION

__all__ = (
"decode_shinylive_url",
"encode_shinylive_url",
"create_shinylive_url",
"create_shinylive_bundle_text",
"create_shinylive_bundle_file",
)
30 changes: 24 additions & 6 deletions shinylive/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
import click

from . import _assets, _deps, _export, _version
from ._url import decode_shinylive_url, encode_shinylive_url
from ._url import (
create_shinylive_bundle_file,
create_shinylive_bundle_text,
create_shinylive_url,
decode_shinylive_url,
)
from ._utils import print_as_json


Expand Down Expand Up @@ -519,6 +524,9 @@ def url() -> None:
@click.option(
"-v", "--view", is_flag=True, default=False, help="Open the link in a browser."
)
@click.option(
"--json", is_flag=True, default=False, help="Print the bundle as JSON to stdout."
)
@click.option(
"--no-header", is_flag=True, default=False, help="Hide the Shinylive header."
)
Expand All @@ -529,6 +537,7 @@ def encode(
files: Optional[tuple[str, ...]] = None,
mode: Literal["editor", "app"] = "editor",
language: Optional[str] = None,
json: bool = False,
no_header: bool = False,
view: bool = False,
) -> None:
Expand All @@ -549,15 +558,24 @@ def encode(
else:
lang = None

url = encode_shinylive_url(
app=app_in,
files=files,
if "\n" in app_in:
bundle = create_shinylive_bundle_text(app_in, files, lang)
else:
bundle = create_shinylive_bundle_file(app_in, files, lang)

if json:
print_as_json(bundle["files"])
if not view:
return

url = create_shinylive_url(
bundle,
mode=mode,
language=lang,
header=not no_header,
)

print(url)
if not json:
print(url)

if view:
import webbrowser
Expand Down
106 changes: 74 additions & 32 deletions shinylive/_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,55 @@ class FileContentJson(TypedDict):
type: NotRequired[Literal["text", "binary"]]


def encode_shinylive_url(
app: str | Path,
files: Optional[str | Path | Sequence[str | Path]] = None,
class AppBundle(TypedDict):
language: Literal["py", "r"]
files: list[FileContentJson]


def create_shinylive_url(
bundle: AppBundle,
mode: Literal["editor", "app"] = "editor",
language: Optional[Literal["py", "r"]] = None,
header: bool = True,
) -> str:
""" """

file_lz = lzstring_file_bundle(bundle["files"])

base = "https://shinylive.io"
h = "h=0&" if not header and mode == "app" else ""

return f"{base}/{bundle['language']}/{mode}/#{h}code={file_lz}"


def create_shinylive_bundle_text(
app: str,
files: Optional[str | Path | Sequence[str | Path]] = None,
language: Optional[Literal["py", "r"]] = None,
root_dir: str | Path = ".",
) -> AppBundle:
if language is None:
language = detect_app_language(app)
elif language not in ["py", "r"]:
raise ValueError(
f"Language '{language}' is not supported. Please specify one of 'py' or 'r'."
)

app_fc: FileContentJson = {
"name": f"app.{'py' if language == 'py' else 'R'}",
"content": app,
}

return {
"language": language,
"files": add_supporting_files_to_bundle(app_fc, files, root_dir),
}


def create_shinylive_bundle_file(
app: str | Path,
files: Optional[str | Path | Sequence[str | Path]] = None,
language: Optional[Literal["py", "r"]] = None,
) -> AppBundle:
"""
Generate a URL for a [ShinyLive application](https://shinylive.io).
Expand Down Expand Up @@ -57,20 +99,34 @@ def encode_shinylive_url(

if language is None:
language = detect_app_language(app)
elif language not in ["py", "r"]:
raise ValueError(
f"Language '{language}' is not supported. Please specify one of 'py' or 'r'."
)

# if app has a newline, then it's app content, not a path
if isinstance(app, str) and "\n" in app:
app_path = ""
root_dir = Path(".")
app_fc: FileContentJson = {
"name": f"app.{'py' if language == 'py' else 'R'}",
"content": app,
}
file_bundle = [app_fc]
else:
app_path = Path(app)
root_dir = app_path.parent
file_bundle = [read_file(app, root_dir)]
app_path = Path(app)
root_dir = app_path.parent
app_fc = read_file(app, root_dir)

# if the app is not named either `ui.R` or `server.R`, then make it app.py or app.R
if app_fc["name"] not in ["ui.R", "server.R"]:
app_fc["name"] = f"app.{'py' if language == 'py' else 'R'}"

return {
"language": language,
"files": add_supporting_files_to_bundle(app_fc, files, root_dir, app_path),
}


def add_supporting_files_to_bundle(
app: FileContentJson,
files: Optional[str | Path | Sequence[str | Path]] = None,
root_dir: str | Path = ".",
app_path: str | Path = "",
) -> list[FileContentJson]:
app_path = Path(app_path)

file_bundle = [app]

if isinstance(files, (str, Path)):
files = [files]
Expand All @@ -88,21 +144,7 @@ def encode_shinylive_url(
read_file(file, root_dir) for file in file_list if Path(file) != app_path
]

if language not in ["py", "r"]:
raise ValueError(
f"Language '{language}' is not supported. Please specify one of 'py' or 'r'."
)

# if first file is not named either `ui.R` or `server.R`, then make it app.{language}
if file_bundle[0]["name"] not in ["ui.R", "server.R"]:
file_bundle[0]["name"] = f"app.{'py' if language == 'py' else 'R'}"

file_lz = lzstring_file_bundle(file_bundle)

base = "https://shinylive.io"
h = "h=0&" if not header and mode == "app" else ""

return f"{base}/{language}/{mode}/#{h}code={file_lz}"
return file_bundle


def detect_app_language(app: str | Path) -> Literal["py", "r"]:
Expand Down

0 comments on commit 373f639

Please sign in to comment.