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.
|
|
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(
|
|
208
|
-
return {"sum":
|
|
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":
|
|
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\
|
package/esm/src/vite/mod.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
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
|
-
|
|
11
|
-
from fastapi
|
|
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
|
-
|
|
22
|
-
return app # return the app object
|
|
19
|
+
root_dir = Path(args.root).absolute()
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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.
|
|
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",
|