Skip to content

Commit 3552c8e

Browse files
committed
Add DuckDB virtual server for Python
Signed-off-by: Andrew Stein <[email protected]>
1 parent 2c00d9d commit 3552c8e

File tree

5 files changed

+586
-0
lines changed

5 files changed

+586
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
5+
<link rel="stylesheet" crossorigin="anonymous" href="/node_modules/@finos/perspective-viewer/dist/css/themes.css" />
6+
<style>
7+
perspective-viewer {
8+
position: absolute;
9+
inset: 0;
10+
}
11+
</style>
12+
</head>
13+
<body>
14+
<perspective-viewer id="viewer" ,> </perspective-viewer>
15+
<script type="module">
16+
import "/node_modules/@finos/perspective-viewer/dist/cdn/perspective-viewer.js";
17+
import "/node_modules/@finos/perspective-viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js";
18+
import "/node_modules/@finos/perspective-viewer-d3fc/dist/cdn/perspective-viewer-d3fc.js";
19+
import perspective from "/node_modules/@finos/perspective/dist/cdn/perspective.js";
20+
const viewer = document.getElementById("viewer");
21+
22+
// Create a client that expects a Perspective server to accept
23+
// Websocket connections at the specified URL.
24+
const websocket = await perspective.websocket("ws://localhost:3000/websocket");
25+
const table = await websocket.open_table("data_source_one");
26+
27+
// Load this in the `<perspective-viewer>`.
28+
viewer.load(table);
29+
</script>
30+
</body>
31+
</html>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "python-duckdb-virtual",
3+
"private": true,
4+
"version": "3.7.4",
5+
"description": "An example of streaming a `perspective-python` server to the browser.",
6+
"scripts": {
7+
"start": "PYTHONPATH=../../python/perspective python3 server.py"
8+
},
9+
"keywords": [],
10+
"license": "Apache-2.0",
11+
"dependencies": {
12+
"@finos/perspective": "workspace:^",
13+
"@finos/perspective-viewer": "workspace:^",
14+
"@finos/perspective-viewer-d3fc": "workspace:^",
15+
"@finos/perspective-viewer-datagrid": "workspace:^",
16+
"@finos/perspective-workspace": "workspace:^",
17+
"superstore-arrow": "catalog:"
18+
},
19+
"devDependencies": {
20+
"npm-run-all": "catalog:"
21+
}
22+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2+
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3+
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4+
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5+
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6+
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7+
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
8+
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9+
# ┃ This file is part of the Perspective library, distributed under the terms ┃
10+
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11+
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12+
13+
from pathlib import Path
14+
15+
import duckdb
16+
import perspective
17+
import perspective.handlers.tornado
18+
import perspective.virtual_servers.duckdb
19+
import tornado.ioloop
20+
import tornado.web
21+
import tornado.websocket
22+
23+
from loguru import logger
24+
from tornado.web import StaticFileHandler
25+
26+
27+
INPUT_FILE = (
28+
Path(__file__).parent.resolve()
29+
/ "node_modules"
30+
/ "superstore-arrow"
31+
/ "superstore.parquet"
32+
)
33+
34+
35+
if __name__ == "__main__":
36+
db = duckdb.connect(":memory:perspective")
37+
db.sql(
38+
f"""
39+
SET default_null_order=NULLS_FIRST_ON_ASC_LAST_ON_DESC;
40+
CREATE TABLE data_source_one AS
41+
SELECT * FROM '{INPUT_FILE}';
42+
""",
43+
)
44+
45+
virtual_server = perspective.virtual_servers.duckdb.DuckDBVirtualServer(db)
46+
app = tornado.web.Application(
47+
[
48+
(
49+
r"/websocket",
50+
perspective.handlers.tornado.PerspectiveTornadoHandler,
51+
{"perspective_server": virtual_server},
52+
),
53+
(r"/node_modules/(.*)", StaticFileHandler, {"path": "../../node_modules/"}),
54+
(
55+
r"/(.*)",
56+
StaticFileHandler,
57+
{"path": "./", "default_filename": "index.html"},
58+
),
59+
],
60+
websocket_max_message_size=100 * 1024 * 1024,
61+
)
62+
63+
app.listen(3000)
64+
logger.info("Listening on http://localhost:3000")
65+
loop = tornado.ioloop.IOLoop.current()
66+
loop.start()

pnpm-lock.yaml

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)