sveltekit-python-vercel 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -101,9 +101,11 @@ Using [Poetry](https://python-poetry.org/) to manage your virtual environments w
101
101
 
102
102
  [tool.poetry.dependencies]
103
103
  python = "^3.9"
104
- fastapi = "^0.95.1"
104
+ fastapi = "^0.95.2"
105
105
  uvicorn = "^0.22.0"
106
-
106
+
107
+ [tool.poetry.group.dev.dependencies]
108
+ watchfiles = "^0.19.0"
107
109
 
108
110
  [build-system]
109
111
  requires = ["poetry-core"]
@@ -204,12 +206,12 @@ Note:
204
206
  b: float
205
207
 
206
208
 
207
- async def POST(numberSet: NumberSet):
208
- return {"sum": float(numberSet.a) + float(numberSet.b)}
209
+ async def POST(data: NumberSet):
210
+ return {"sum": data.a + data.b}
209
211
 
210
212
 
211
- async def GET(a, b):
212
- return {"sum": float(a) + float(b)}
213
+ async def GET(a: float, b: float):
214
+ return {"sum": a + b}
213
215
 
214
216
  ```
215
217
 
@@ -228,8 +230,9 @@ Check out the awesome [sveltekit-modal](https://github.com/semicognitive/sveltek
228
230
 
229
231
  ## Possible future plans
230
232
 
233
+ - [X] Add hot reloading in dev mode
231
234
  - [ ] Generate endpoints (/api folder) automatically during build
232
235
  - [ ] Auto create requirements.txt from pyproject.toml (both related to vercel functions being checked/handled before build)
233
236
  - [ ] Add form actions
234
237
  - [ ] Add load functions
235
- - [ ] Add helper functions to automatically call API endpoints in project
238
+ - [ ] Add helper functions to automatically call API endpoints in project\
@@ -14,10 +14,9 @@ const get_pyServerEndpointAsString = (app_url, serve = false) => `
14
14
  fullURL = new URL('/api' + url.pathname, new URL('${app_url}')) + url.search;
15
15
  }
16
16
 
17
- console.log(\`Reached python endpoint of \${method} \${fullURL}\`)
17
+ console.log(\`PY: Reached python endpoint of \${method} \${fullURL}\`)
18
18
  let requestBody = await request.clone().text();
19
- console.log(\`Body: \${requestBody}\`);
20
- console.log(\`Content-Type: \${request.headers.get('content-type')}\`);
19
+ console.log(\`PY: Body: \${requestBody}\`);
21
20
 
22
21
  if (method === 'GET') {
23
22
  requestBody = null;
@@ -79,11 +78,11 @@ export async function sveltekit_python_vercel(opts = {}) {
79
78
  name: "vite-plugin-sveltekit_python-build",
80
79
  apply: "build",
81
80
  async configResolved(config) {
82
- console.log("BUILD DEBUG");
83
- console.log("ROOT PATH: " + config.root);
84
- console.log("LOADED VERCEL URL: " + loadEnv("", config.root, "").VERCEL_URL);
81
+ console.log("PY: BUILD DEBUG");
82
+ console.log("PY: ROOT PATH: " + config.root);
83
+ console.log("PY: LOADED VERCEL URL: " + loadEnv("", config.root, "").VERCEL_URL);
85
84
  const packagelocation = path.join(config.root, "node_modules", "sveltekit-python-vercel", "esm/src/vite");
86
- console.log("PACKAGE LOCATION: " + packagelocation);
85
+ console.log("PY: PACKAGE LOCATION: " + packagelocation);
87
86
  const python_path = opts.python_path ?? (await which("python3"));
88
87
  await run$ `cd ${packagelocation}`;
89
88
  await run$ `${python_path} ${packagelocation}/sveltekit_python_vercel/build.py --root ${config.root}`;
@@ -95,7 +94,7 @@ export async function sveltekit_python_vercel(opts = {}) {
95
94
  const api_url = path.join(httpPrefix + loadEnv("", config.root, "").VERCEL_URL);
96
95
  // get current Vercel deploy URL
97
96
  sveltekit_url = new URL(api_url);
98
- console.log("Build API URL: " + sveltekit_url.toString());
97
+ console.log("PY: Build API URL: " + sveltekit_url.toString());
99
98
  },
100
99
  };
101
100
  const plugin_py_server_endpoint_serve = {
@@ -2,7 +2,7 @@ import argparse
2
2
  import shutil
3
3
  import glob
4
4
 
5
- from pathlib import Path
5
+ from pathlib import Path, PurePosixPath
6
6
 
7
7
  parser = argparse.ArgumentParser(description="Run Sveltekit Python Deployment")
8
8
  parser.add_argument("--root", default=".", help="Root directory of Vercel project")
@@ -25,7 +25,12 @@ for module_path in glob.glob(str(root_dir / 'src/routes/**/+server.py'), recursi
25
25
 
26
26
  # replace the root_dir with api_dir
27
27
  api_route = api_dir / Path(module_path).absolute().relative_to(root_dir / "src/routes")
28
+
29
+ # replace square brackets with curly brackets
28
30
  api_route = Path(str(api_route).replace('[', '{').replace(']', '}'))
31
+
32
+ # remove any groups from the URL
33
+ api_route = Path(str(PurePosixPath(*[part for part in PurePosixPath(api_route).parts if not part.startswith("(") and not part.endswith(")")])))
29
34
 
30
35
  if not api_route.parent.exists():
31
36
  api_route.parent.mkdir(parents=True)
@@ -1,8 +1,8 @@
1
- import os
2
1
  import glob
3
2
  import importlib
4
3
  import importlib.util
5
- from pathlib import Path
4
+ import os
5
+ from pathlib import Path, PurePosixPath
6
6
 
7
7
  from fastapi import FastAPI, Request
8
8
  from fastapi.responses import JSONResponse
@@ -25,29 +25,27 @@ for module_path in glob.glob('./**/+server.py', recursive=True):
25
25
 
26
26
  # Replace square brackets with curly brackets
27
27
  api_route = api_route.replace('[', '{').replace(']', '}')
28
+
29
+ # remove any groups from the URL
30
+ api_route = str(PurePosixPath(*[part for part in PurePosixPath(api_route).parts if not part.startswith("(") and not part.endswith(")")]))
28
31
 
29
32
  mod = importlib.import_module(module_name, module_package)
30
-
31
- if hasattr(mod, 'GET'):
32
- app.add_api_route(api_route, mod.GET, methods=["GET"])
33
- print(f"PYTHON ENDPOINT: Added {module_path} [GET] at {api_route}")
34
-
35
- if hasattr(mod, 'POST'):
36
- app.add_api_route(api_route, mod.POST, methods=["POST"])
37
- print(f"PYTHON ENDPOINT: Added {module_path} [POST] at {api_route}")
38
-
39
- if hasattr(mod, 'PATCH'):
40
- app.add_api_route(api_route, mod.PATCH, methods=["PATCH"])
41
- print(f"PYTHON ENDPOINT: Added {module_path} [PATCH] at {api_route}")
42
-
43
- if hasattr(mod, 'PUT'):
44
- app.add_api_route(api_route, mod.PUT, methods=["PUT"])
45
- print(f"PYTHON ENDPOINT: Added {module_path} [PUT] at {api_route}")
46
-
47
- if hasattr(mod, 'DELETE'):
48
- app.add_api_route(api_route, mod.DELETE, methods=["DELETE"])
49
- print(f"PYTHON ENDPOINT: Added {module_path} [DELETE] at {api_route}")
50
-
33
+
34
+ # Add endpoints
35
+ for method in ["GET", "POST", "PATCH", "PUT", "DELETE"]:
36
+
37
+ # Check for duplicate methods
38
+ if hasattr(mod, method) and hasattr(mod, method.lower()):
39
+ raise Exception(
40
+ f"Duplicate method {method} and {method.lower()} in {api_route}"
41
+ )
42
+
43
+ elif hasattr(mod, method):
44
+ app.add_api_route(api_route, getattr(mod, method), methods=[method])
45
+ print(f"PYTHON ENDPOINT: Added {module_path} [{method}] at {api_route}")
46
+ elif hasattr(mod, method.lower()):
47
+ app.add_api_route(api_route, getattr(mod, method.lower()), methods=[method])
48
+ print(f"PYTHON ENDPOINT: Added {module_path} [{method}] at {api_route}")
51
49
 
52
50
  @app.exception_handler(Exception)
53
51
  async def unicorn_exception_handler(request: Request, exc: Exception):
@@ -1,14 +1,12 @@
1
- import uvicorn
2
1
  import argparse
3
- import os
2
+ import glob
4
3
  import importlib
5
4
  import importlib.util
6
- import glob
7
5
  import shutil
8
- from pathlib import Path
6
+ from pathlib import Path, PurePosixPath
9
7
 
10
- from fastapi import FastAPI, Request
11
- from fastapi.responses import JSONResponse
8
+ import uvicorn
9
+ from fastapi import FastAPI
12
10
 
13
11
  parser = argparse.ArgumentParser(description="Run Sveltekit Python Server")
14
12
  parser.add_argument("--host", default="0.0.0.0", help="Server hostname")
@@ -18,62 +16,67 @@ args = parser.parse_args()
18
16
 
19
17
  app = FastAPI()
20
18
 
21
- def app_factory():
22
- return app # return the app object
19
+ root_dir = Path(args.root).absolute()
23
20
 
24
- if __name__ == "__main__":
25
-
26
- root_dir = Path(args.root).absolute()
27
- api_dir = Path("./sveltekit_python_vercel").absolute()
28
-
29
- # Add all +server.py routes to web_app
30
- for module_path in glob.glob(str(root_dir / 'src/routes/**/+server.py'), recursive=True):
31
-
32
- # replace the root_dir with api_dir
33
- api_route = api_dir / Path(module_path).absolute().relative_to(root_dir/ "src/routes")
34
-
35
- if not api_route.parent.exists():
36
- api_route.parent.mkdir(parents=True)
37
-
38
- # copy module path to api_route
39
- shutil.copy(module_path, api_route.parent)
40
- print(f"PYTHON ENDPOINT: Copied {module_path} to {api_route.parent}")
41
-
42
- # Get the module name from the module path
43
- module_name = api_route.stem
44
-
45
- # Import the module dynamically
46
- spec = importlib.util.spec_from_file_location(module_name, api_route)
47
- mod = importlib.util.module_from_spec(spec)
48
- spec.loader.exec_module(mod)
49
-
50
- # Get the relative path of the module from the API directory
51
- rel_path = api_route.relative_to(api_dir)
52
- # Convert the relative path to a string and remove the file extension
53
- api_path = "/" + str(rel_path.parent)
54
-
55
- # Replace square brackets with curly brackets
56
- api_path = api_path.replace('[', '{').replace(']', '}')
57
-
58
- print("ADDING API PATH:", rel_path, api_path)
59
-
60
- if hasattr(mod, 'GET'):
61
- app.add_api_route(api_path, mod.GET, methods=["GET"])
62
-
63
- if hasattr(mod, 'POST'):
64
- app.add_api_route(api_path, mod.POST, methods=["POST"])
65
-
66
- if hasattr(mod, 'PATCH'):
67
- app.add_api_route(api_path, mod.PATCH, methods=["PATCH"])
68
-
69
- if hasattr(mod, 'PUT'):
70
- app.add_api_route(api_path, mod.PUT, methods=["PUT"])
71
-
72
- if hasattr(mod, 'DELETE'):
73
- app.add_api_route(api_path, mod.DELETE, methods=["DELETE"])
21
+ api_dir = Path("./sveltekit_python_vercel").absolute()
22
+
23
+ route_dir = root_dir.joinpath("src/routes")
24
+
25
+ watch_modules = [] # list of modules to watch for changes
26
+
27
+ for module_path in glob.glob(
28
+ route_dir.joinpath("**/+server.py").as_posix(), recursive=True
29
+ ):
30
+ abs_module_path = Path(module_path).absolute()
31
+
32
+ watch_modules.append(abs_module_path.parent.as_posix())
33
+
34
+ api_route = api_dir.joinpath(abs_module_path.relative_to(root_dir / "src/routes"))
74
35
 
36
+ if not api_route.parent.exists():
37
+ api_route.parent.mkdir(parents=True)
38
+
39
+ # copy module path to api_route
40
+ shutil.copy(module_path, api_route.parent)
41
+
42
+ module_name = api_route.stem
43
+
44
+ spec = importlib.util.spec_from_file_location(module_name, api_route)
45
+ mod = importlib.util.module_from_spec(spec)
46
+ spec.loader.exec_module(mod)
47
+
48
+ # Get the relative path of the module from the API directory
49
+ rel_path = api_route.relative_to(api_dir)
50
+
51
+ # Convert the relative path to a string and remove the file extension
52
+ api_path = f"/{rel_path.parent}"
53
+
54
+ # Replace square brackets with curly brackets
55
+ api_path = api_path.replace("[", "{").replace("]", "}")
75
56
 
76
- config = uvicorn.Config(app_factory, host=args.host, port=args.port, log_level="info", factory=True)
77
- server = uvicorn.Server(config)
78
- print(f"Hosting on http://{args.host}:{args.port}")
79
- server.run()
57
+ # remove any groups from the URL
58
+ api_path = str(PurePosixPath(*[part for part in PurePosixPath(api_path).parts if not part.startswith("(") and not part.endswith(")")]))
59
+
60
+ # Add endpoints
61
+ for method in ["GET", "POST", "PATCH", "PUT", "DELETE"]:
62
+ # Check for duplicate methods
63
+ if hasattr(mod, method) and hasattr(mod, method.lower()):
64
+ raise Exception(
65
+ f"Duplicate method {method} and {method.lower()} in {api_route}"
66
+ )
67
+ elif hasattr(mod, method):
68
+ app.add_api_route(api_path, getattr(mod, method), methods=[method])
69
+ elif hasattr(mod, method.lower()):
70
+ app.add_api_route(api_path, getattr(mod, method.lower()), methods=[method])
71
+
72
+
73
+ if __name__ == "__main__":
74
+ uvicorn.run(
75
+ "sveltekit_python_vercel.serve:app",
76
+ host=args.host,
77
+ port=args.port,
78
+ log_level="info",
79
+ reload=True,
80
+ reload_includes=[*set(watch_modules)],
81
+ reload_excludes=[api_dir.as_posix()],
82
+ )
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "module": "./esm/mod.js",
3
3
  "types": "./types/mod.d.ts",
4
4
  "name": "sveltekit-python-vercel",
5
- "version": "v0.3.0",
5
+ "version": "v0.4.1",
6
6
  "description": "Write Sveltekit server endpoints in Python and seamlessly deploy to Vercel",
7
7
  "repository": {
8
8
  "type": "git",