Skip to content

Commit

Permalink
Merge pull request #27 from gdsfactory/kweb-1.0
Browse files Browse the repository at this point in the history
KWeb 1.0
  • Loading branch information
sebastian-goeldi authored Aug 20, 2023
2 parents 26a7957 + 33b4546 commit db8618e
Show file tree
Hide file tree
Showing 21 changed files with 12,700 additions and 450 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,8 @@ dmypy.json

# Pyre type checker
.pyre/

#css/bootstrap/npm
package-lock.json
package.json
node_modules
19 changes: 9 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
exclude: |
(?x)(
^src/kweb/static/bootstrap/
)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v4.4.0"
Expand All @@ -15,11 +19,6 @@ repos:
- id: requirements-txt-fixer
- id: trailing-whitespace

- repo: https://github.com/hakancelik96/unimport
rev: 0.14.1
hooks:
- id: unimport
args: [--remove, --include-star-import]
- repo: https://github.com/pycqa/isort
rev: "5.12.0"
hooks:
Expand All @@ -28,7 +27,7 @@ repos:
args: ["--profile", "black", "--filter-files"]

- repo: https://github.com/psf/black
rev: "23.1.0"
rev: "23.7.0"
hooks:
- id: black

Expand All @@ -44,7 +43,7 @@ repos:
files: ".ipynb"

- repo: https://github.com/asottile/pyupgrade
rev: v3.3.1
rev: v3.10.1
hooks:
- id: pyupgrade
args: [--py310-plus, --keep-runtime-typing]
Expand All @@ -56,7 +55,7 @@ repos:
# args: ["-L TE,TE/TM,te,ba,FPR,fpr_spacing,ro,donot"]

- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.9.0.2
rev: v0.9.0.5
hooks:
- id: shellcheck

Expand All @@ -66,7 +65,7 @@ repos:
# - id: python-use-type-annotations

- repo: https://github.com/PyCQA/bandit
rev: 1.7.4
rev: 1.7.5
hooks:
- id: bandit
args: [--exit-zero]
Expand Down Expand Up @@ -137,6 +136,6 @@ repos:
# # - id: nbqa-isort
# # args: ["--float-to-top"]
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: "v0.0.253"
rev: "v0.0.285"
hooks:
- id: ruff
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# kweb 0.1.1

KLayout Web Viewer ![demo](https://i.imgur.com/HPvePvX.png)
KLayout Web Viewer ![demo](docs/_static/kweb.png)

Based on https://github.com/klayoutmatthias/canvas2canvas

Expand All @@ -26,11 +26,14 @@ Install the necessary dependecies

`make install`

## Set a folder for kweb to use when looking for gds files

`export KWEB_FILESLOCATION=/path/to/folder/with/file.gds`

## Run

`cd src/kweb`

`make run`

Copy the link http://127.0.0.1:8000/gds/wg to your browser to open the waveguide example
Copy the link http://127.0.0.1:8000/gds/file.gds (or http://localhost:8000/gds/file.gds also works) to your browser to open the waveguide example
Binary file added docs/_static/kweb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 3 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ name = "kweb"
description = "KLayout API implementation of gdsfactory"
readme = "README.md"
classifiers = [
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Operating System :: OS Independent",
]
version = "0.1.1"
requires-python = ">=3.10"
version = "1.0.0"
authors = [
{name = "gdsfactory community", email = "[email protected]"},
]
dependencies = [
"klayout >= 0.28.3",
"klayout >= 0.28.11",
"fastapi",
"uvicorn[standard]",
"jinja2",
Expand Down Expand Up @@ -73,13 +71,6 @@ exclude = ''' # Specify the files/dirs that should be ignored by the black form
)/
'''

[tool.commitizen]
name = "cz_conventional_commits"
version = "0.1.1"
version_files = [
"pyproject.toml:version",
]

[tool.mypy]
python_version = "3.10"
strict = true
Expand Down
Empty file added src/kweb/custom.css
Empty file.
Binary file removed src/kweb/gds_files/wg.gds
Binary file not shown.
114 changes: 50 additions & 64 deletions src/kweb/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import pathlib
import tempfile
from glob import glob
import os
from pathlib import Path
from typing import Any

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.exceptions import HTTPException
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from starlette.routing import WebSocketRoute
Expand All @@ -14,91 +13,78 @@
from kweb import __version__ as version
from kweb.server import LayoutViewServerEndpoint

# module_path = Path(os.getenv("KWEB_EDAFILES", Path(__file__).parent.resolve()))
module_path = Path(__file__).parent.absolute()
home_path = Path.home() / ".gdsfactory" / "extra"
home_path.mkdir(exist_ok=True, parents=True)

app = FastAPI(routes=[WebSocketRoute("/gds/ws", endpoint=LayoutViewServerEndpoint)])
app.mount("/static", StaticFiles(directory=module_path / "static"), name="static")
tmp = pathlib.Path(tempfile.TemporaryDirectory().name).parent / "gdsfactory"
tmp.mkdir(exist_ok=True, parents=True)
local_gds_files = module_path / "gds_files"
edafiles = Path(os.getenv("KWEB_FILESLOCATION", local_gds_files))

app = FastAPI(routes=[WebSocketRoute("/gds/ws", endpoint=LayoutViewServerEndpoint)])
app.mount("/static", StaticFiles(directory=module_path / "static"), name="kweb_static")
templates = Jinja2Templates(directory=module_path / "templates")


@app.get("/")
async def root(request: Request) -> _TemplateResponse:
files_root = tmp
paths_list = glob(str(files_root / "*.gds"))
files_list = sorted(Path(gdsfile).name for gdsfile in paths_list)
files_metadata = [
{"name": file_name, "url": f"gds/{file_name}"} for file_name in files_list
]
return templates.TemplateResponse(
"file_browser.html",
{
"request": request,
"message": "Welcome to kweb visualizer",
"files_root": files_root,
"files_metadata": files_metadata,
},
)


@app.get("/gds", response_class=HTMLResponse)
async def gds_view(
request: Request, gds_file: str, layer_props: str = str(home_path)
@app.get("/gds/{gds_name:path}", response_class=HTMLResponse)
async def gds_view_static(
request: Request,
gds_name: str,
layer_props: str | None = None,
cell: str | None = None,
) -> _TemplateResponse:
url = str(
request.url.scheme
+ "://"
+ (request.url.hostname or "localhost")
+ ":"
+ str(request.url.port)
+ "/gds"
)
return templates.TemplateResponse(
"client.html",
{
"request": request,
"url": url,
"gds_file": gds_file,
"layer_props": layer_props,
},
)
gds_file = (edafiles / f"{gds_name}").with_suffix(".gds")

exists = gds_file.exists() and gds_file.is_file() and gds_file.stat().st_mode

@app.get("/gds/{gds_name}.gds")
async def gds_view_static_redirect(gds_name: str):
return RedirectResponse(f"/gds/{gds_name}")
if not exists:
raise HTTPException(
status_code=404,
detail=f'No gds found with name "{gds_name}".'
" It doesn't exist or is not accessible",
)

root_path = request.scope["root_path"]

@app.get("/gds/{gds_name}", response_class=HTMLResponse)
async def gds_view_static(
request: Request, gds_name: str, layer_props: str = str(home_path)
) -> _TemplateResponse:
gds_file = (tmp / f"{gds_name}").with_suffix(".gds")
match request.url.scheme:
case "https":
ws_scheme = "wss://"
case "http":
ws_scheme = "ws://"
case other:
raise HTTPException(status_code=406, detail=f"Unknown scheme {other}")

url = str(
request.url.scheme
+ "://"
url = (
ws_scheme
+ (request.url.hostname or "localhost")
+ ":"
+ str(request.url.port)
+ root_path
+ "/gds"
)

template_params = {
"request": request,
"url": url,
"gds_file": gds_file,
"layer_props": layer_props,
}

if cell is not None:
template_params["cell"] = cell

return templates.TemplateResponse(
"client.html",
{
"request": request,
"url": url,
"gds_file": gds_file,
"layer_props": layer_props,
},
template_params,
)


@app.get("/status")
async def status() -> dict[str, Any]:
return {"server": "kweb", "version": version}


if __name__ == "__main__":
import uvicorn

uvicorn.run(app)
Loading

0 comments on commit db8618e

Please sign in to comment.