Skip to content

Commit

Permalink
Merge pull request #2050 from Skilles/main
Browse files Browse the repository at this point in the history
Allow client to download raw data from server
  • Loading branch information
falkoschindler authored Nov 22, 2023
2 parents bde65e0 + 9dbf8b9 commit 995c886
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 13 deletions.
6 changes: 3 additions & 3 deletions nicegui/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ def open(self, target: Union[Callable[..., Any], str], new_tab: bool = False) ->
path = target if isinstance(target, str) else self.page_routes[target]
outbox.enqueue_message('open', {'path': path, 'new_tab': new_tab}, self.id)

def download(self, url: str, filename: Optional[str] = None) -> None:
"""Download a file from the given URL."""
outbox.enqueue_message('download', {'url': url, 'filename': filename}, self.id)
def download(self, src: Union[str, bytes], filename: Optional[str] = None) -> None:
"""Download a file from a given URL or raw bytes."""
outbox.enqueue_message('download', {'src': src, 'filename': filename}, self.id)

def on_connect(self, handler: Union[Callable[..., Any], Awaitable]) -> None:
"""Register a callback to be called when the client connects."""
Expand Down
15 changes: 8 additions & 7 deletions nicegui/functions/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
from .. import context, core, helpers


def download(src: Union[str, Path], filename: Optional[str] = None) -> None:
def download(src: Union[str, Path, bytes], filename: Optional[str] = None) -> None:
"""Download
Function to trigger the download of a file.
Function to trigger the download of a file, URL or bytes.
:param src: target URL or local path of the file which should be downloaded
:param src: target URL, local path of a file or raw data which should be downloaded
:param filename: name of the file to download (default: name of the file on the server)
"""
if helpers.is_file(src):
src = core.app.add_static_file(local_file=src, single_use=True)
else:
src = str(src)
if not isinstance(src, bytes):
if helpers.is_file(src):
src = core.app.add_static_file(local_file=src, single_use=True)
else:
src = str(src)
context.get_client().download(src, filename)
9 changes: 6 additions & 3 deletions nicegui/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,17 @@
});
}

function download(url, filename) {
function download(src, filename) {
const anchor = document.createElement("a");
anchor.href = url;
anchor.href = typeof src === "string" ? src : URL.createObjectURL(new Blob([src]));
anchor.target = "_blank";
anchor.download = filename || "";
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
if (typeof src !== "string") {
URL.revokeObjectURL(url);
}
}

async function loadDependencies(element) {
Expand Down Expand Up @@ -297,7 +300,7 @@
const target = msg.new_tab ? '_blank' : '_self';
window.open(url, target);
},
download: (msg) => download(msg.url, msg.filename),
download: (msg) => download(msg.src, msg.filename),
notify: (msg) => Quasar.Notify.create(msg),
};
const socketMessageQueue = [];
Expand Down
9 changes: 9 additions & 0 deletions tests/test_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,12 @@ def test_downloading_local_file_as_src(screen: Screen):
screen.wait(0.5)
assert (DOWNLOAD_DIR / 'slide1.jpg').exists()
assert len(app.routes) == route_count_before_download


def test_download_raw_data(screen: Screen):
ui.button('download', on_click=lambda: ui.download(b'test', 'test.txt'))

screen.open('/')
screen.click('download')
screen.wait(0.5)
assert (DOWNLOAD_DIR / 'test.txt').read_text() == 'test'

0 comments on commit 995c886

Please sign in to comment.