Open cakir-enes opened 1 year ago
Hi @cakir-enes - can you provide an example of the code where you're trying to remove records, so we can help you?
+1 for this, when I noticed it ages ago it could be repoed by creating a table in python, connect web viewer, asyncio.sleep for 30 seconds table.remove([key]) in python. Observe that they key still exists in Web viewer. I'll see if I can get something specific next week.
It seemed to me that the ws protocol couldn't really deal with deletes.
Fyi a workaround is to have a second ws and manually call remove in javascript on the table...
As promised too long ago, notice that data is updated and added OK and the ws is sending something on delete.
The workaround is to add a second ws and just send messages to your own js code to call delete in javascript...
As a side note this might make a good example for new developers as its quite hard to get started on the whole thing otherwise...
# pip install 'uvicorn[standard] fastapi perspective-python pandas
import asyncio
import logging
import threading
import uvicorn
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from starlette.responses import HTMLResponse
import pandas as pd
from perspective import Table, PerspectiveManager, PerspectiveStarletteHandler
def perspective_thread(manager):
"""Perspective application thread starts its own event loop, and
adds the table with the name "data_source_one", which will be used
in the front-end."""
psp_loop = asyncio.new_event_loop()
manager.set_loop_callback(psp_loop.call_soon_threadsafe)
data = pd.DataFrame({
"index": list(range(100)),
"float": [i * 1.5 for i in range(100)],
"bool": [True for i in range(100)],
"string": [str(i) for i in range(100)]
})
table = Table(data, index="index")
manager.host_table("data_source", table)
async def deleteme():
for i in range(100):
print("DELETEING", i)
table.remove([i])
print(table.num_rows())
print("Adding Junk")
table.update({'index': [i+100], 'float': [1], "bool": [False], 'string': ['newData?']})
table.update({'index': [i+99], 'float': [1], "bool": [False], 'string': ['Modified']})
await asyncio.sleep(10)
psp_loop.run_until_complete(deleteme())
def make_app():
manager = PerspectiveManager()
thread = threading.Thread(target=perspective_thread, args=(manager,))
thread.daemon = True
thread.start()
async def websocket_handler(websocket: WebSocket):
handler = PerspectiveStarletteHandler(manager=manager, websocket=websocket)
await handler.run()
app = FastAPI()
app.add_api_websocket_route("/websocket", websocket_handler)
@app.get("/", response_class=HTMLResponse)
async def read_items():
html_content = """
<!DOCTYPE html>
<html>
<head>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective/dist/cdn/perspective.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/cdn/perspective-viewer.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer-d3fc/dist/cdn/perspective-viewer-d3fc.js"></script>
<link rel="stylesheet" crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/@finos/perspective-viewer/dist/css/pro.css"/>
<script type="module">
import perspective from "https://cdn.jsdelivr.net/npm/@finos/perspective/dist/cdn/perspective.js"
const websocket = perspective.websocket("ws://localhost:8080/websocket")
const worker = perspective.worker();
const server_table = await websocket.open_table("data_source");
const server_view = await server_table.view();
const table = await worker.table(server_view, {
index: await server_table.get_index()
});
document.getElementById('viewer').load(table);
</script>
</head>
<body><perspective-viewer id="viewer" style="width: 500px; height: 500px"></perspective-viewer></body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
return app
if __name__ == "__main__":
app = make_app()
logging.critical("Listening on http://localhost:8080")
uvicorn.run(app, host="0.0.0.0", port=8080)
Not sure if this is the expected behavior, but following this guide https://perspective.finos.org/docs/server/#clientserver-replicated the replica table on client, which is derived by a view that backed by the backend table does not propagate removes.
Is this the expected behavior?
version
2.3.1
, backend :python fastapi