@primate/python 0.4.0 → 0.6.0
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/lib/private/default.d.ts +4 -0
- package/lib/private/default.js +73 -0
- package/lib/private/errors.d.ts +12 -0
- package/lib/private/errors.js +24 -0
- package/lib/private/module.d.ts +13 -0
- package/lib/private/module.js +11 -0
- package/lib/private/runtime.d.ts +4 -0
- package/lib/private/runtime.js +10 -0
- package/lib/private/to-request.d.ts +2 -2
- package/lib/private/to-response.d.ts +2 -2
- package/lib/private/to-response.js +2 -3
- package/lib/private/unwrap.d.ts +3 -2
- package/lib/private/wrapper.d.ts +4 -1
- package/lib/private/wrapper.js +32 -26
- package/lib/public/default.d.ts +1 -3
- package/lib/public/default.js +1 -2
- package/lib/public/runtime.d.ts +1 -3
- package/lib/public/runtime.js +1 -2
- package/package.json +23 -18
- package/lib/private/Default.d.ts +0 -7
- package/lib/private/Default.js +0 -71
- package/lib/private/Runtime.d.ts +0 -6
- package/lib/private/Runtime.js +0 -6
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import E from "#errors";
|
|
2
|
+
import module from "#module";
|
|
3
|
+
import log from "@primate/core/log";
|
|
4
|
+
import server from "@primate/core/server";
|
|
5
|
+
import assert from "@rcompat/assert";
|
|
6
|
+
import fs from "@rcompat/fs";
|
|
7
|
+
import io from "@rcompat/io";
|
|
8
|
+
const PACKAGE = "primate-run";
|
|
9
|
+
const [MAJOR, MINOR] = server.TAG.split(".").map(Number);
|
|
10
|
+
async function show_package() {
|
|
11
|
+
const str0 = () => "";
|
|
12
|
+
let out = await io.run(`pip show ${PACKAGE} 2>/dev/null`).catch(str0);
|
|
13
|
+
if (out.trim().length > 0)
|
|
14
|
+
return out;
|
|
15
|
+
out = await io.run(`uv pip show ${PACKAGE} 2>/dev/null`).catch(str0);
|
|
16
|
+
if (out.trim().length > 0)
|
|
17
|
+
return out;
|
|
18
|
+
out = await io.run(`python -m pip show ${PACKAGE} 2>/dev/null`).catch(str0);
|
|
19
|
+
if (out.trim().length > 0)
|
|
20
|
+
return out;
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
async function check_version() {
|
|
24
|
+
const output = await show_package();
|
|
25
|
+
if (output === null)
|
|
26
|
+
throw E.package_not_found();
|
|
27
|
+
const version_match = output.match(/Version:\s*(\d+)\.(\d+)\.(\d+)/);
|
|
28
|
+
if (version_match === null)
|
|
29
|
+
throw E.package_not_found();
|
|
30
|
+
const [major, minor] = version_match.slice(1).map(Number);
|
|
31
|
+
if (major !== MAJOR || minor !== MINOR)
|
|
32
|
+
throw E.package_mismatch(major, minor);
|
|
33
|
+
log.info("using {0} package {1}.{2}.x", PACKAGE, major, minor);
|
|
34
|
+
}
|
|
35
|
+
export default function default_module(input = {}) {
|
|
36
|
+
const { extension = module.extension } = module.schema.parse(input);
|
|
37
|
+
return {
|
|
38
|
+
name: module.name,
|
|
39
|
+
setup({ onBuild }) {
|
|
40
|
+
onBuild(async (app) => {
|
|
41
|
+
await check_version();
|
|
42
|
+
const requirements_txt = app.root.join("requirements.txt");
|
|
43
|
+
let packages = [];
|
|
44
|
+
if (await requirements_txt.exists()) {
|
|
45
|
+
const requirements = await fs.text(requirements_txt);
|
|
46
|
+
packages = requirements
|
|
47
|
+
.split("\n")
|
|
48
|
+
.filter(line => line.trim().length > 0 && !line.startsWith("#"))
|
|
49
|
+
.map(p => p.trim());
|
|
50
|
+
}
|
|
51
|
+
const packages_str = JSON.stringify(packages);
|
|
52
|
+
app.bind(extension, async (file, { context }) => {
|
|
53
|
+
assert.true(context === "routes", E.only_route_files());
|
|
54
|
+
const relative = file.debase(app.path.routes).path.replace(/^\//, "");
|
|
55
|
+
const source = await file.text();
|
|
56
|
+
return `
|
|
57
|
+
import wrapper from "@primate/python/wrapper";
|
|
58
|
+
import i18n from "app:config:i18n";
|
|
59
|
+
import session from "app:config:session";
|
|
60
|
+
await wrapper(
|
|
61
|
+
${JSON.stringify(source)},
|
|
62
|
+
${packages_str},
|
|
63
|
+
"${PACKAGE}~=${server.TAG}.0",
|
|
64
|
+
"${relative}",
|
|
65
|
+
{ i18n, session }
|
|
66
|
+
);
|
|
67
|
+
`;
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=default.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
declare function only_route_files(): import("@rcompat/error").TemplateError;
|
|
2
|
+
declare function package_not_found(): import("@rcompat/error").TemplateError;
|
|
3
|
+
declare function package_mismatch(major: number, minor: number): import("@rcompat/error").TemplateError;
|
|
4
|
+
declare const errors: {
|
|
5
|
+
only_route_files: typeof only_route_files;
|
|
6
|
+
package_not_found: typeof package_not_found;
|
|
7
|
+
package_mismatch: typeof package_mismatch;
|
|
8
|
+
};
|
|
9
|
+
export type Code = keyof typeof errors;
|
|
10
|
+
export declare const Code: { [K in Code]: K; };
|
|
11
|
+
export default errors;
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import server from "@primate/core/server";
|
|
2
|
+
import error from "@rcompat/error";
|
|
3
|
+
const PACKAGE = "primate-run";
|
|
4
|
+
const t = error.template;
|
|
5
|
+
function only_route_files() {
|
|
6
|
+
return t `python: only route files are supported`;
|
|
7
|
+
}
|
|
8
|
+
function package_not_found() {
|
|
9
|
+
const command = `pip install ${PACKAGE}~=${server.TAG}.0`;
|
|
10
|
+
return t `package not found, run ${command}`;
|
|
11
|
+
}
|
|
12
|
+
function package_mismatch(major, minor) {
|
|
13
|
+
const range = `~> ${server.TAG}.x`;
|
|
14
|
+
const version = `${major}.${minor}.x`;
|
|
15
|
+
return t `${PACKAGE} package version ${version} not in range ${range}`;
|
|
16
|
+
}
|
|
17
|
+
const errors = error.coded({
|
|
18
|
+
only_route_files,
|
|
19
|
+
package_not_found,
|
|
20
|
+
package_mismatch,
|
|
21
|
+
});
|
|
22
|
+
export const Code = Object.fromEntries(Object.keys(errors).map(k => [k, k]));
|
|
23
|
+
export default errors;
|
|
24
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const module: {
|
|
2
|
+
schema: import("pema").ObjectType<import("pema").NormalizeSchemaObject<{
|
|
3
|
+
readonly extension: import("pema").OptionalType<import("pema").StringType>;
|
|
4
|
+
}>, {
|
|
5
|
+
extension: string | undefined;
|
|
6
|
+
}>;
|
|
7
|
+
name: string;
|
|
8
|
+
extension: string;
|
|
9
|
+
};
|
|
10
|
+
type Input = typeof module.schema.input;
|
|
11
|
+
export type { Input };
|
|
12
|
+
export default module;
|
|
13
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type RequestFacade from "@primate/core
|
|
2
|
-
import type Dict from "@rcompat/type
|
|
1
|
+
import type { RequestFacade } from "@primate/core";
|
|
2
|
+
import type { Dict } from "@rcompat/type";
|
|
3
3
|
type FileEntry = {
|
|
4
4
|
bytes: Uint8Array;
|
|
5
5
|
field: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type ResponseLike from "@primate/core/response
|
|
2
|
-
import type Dict from "@rcompat/type
|
|
1
|
+
import { type ResponseLike } from "@primate/core/response";
|
|
2
|
+
import type { Dict } from "@rcompat/type";
|
|
3
3
|
import type { PyProxy } from "pyodide/ffi";
|
|
4
4
|
declare const _default: (response: Dict | PyProxy) => ResponseLike;
|
|
5
5
|
export default _default;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import HANDLER_PROPERTY from "#handler-property";
|
|
2
2
|
import unwrap from "#unwrap";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import view from "@primate/core/response/view";
|
|
3
|
+
import response from "@primate/core/response";
|
|
4
|
+
const { error, redirect, view } = response;
|
|
6
5
|
const handlers = { error, redirect, view };
|
|
7
6
|
const handle_handler = (handler, response) => {
|
|
8
7
|
if (handler === "view") {
|
package/lib/private/unwrap.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type Dict from "@rcompat/type/Dict";
|
|
2
1
|
import type { PyProxy } from "pyodide/ffi";
|
|
3
|
-
export default function unwrap(response: PyProxy):
|
|
2
|
+
export default function unwrap(response: PyProxy): {
|
|
3
|
+
[k: string]: unknown;
|
|
4
|
+
};
|
|
4
5
|
//# sourceMappingURL=unwrap.d.ts.map
|
package/lib/private/wrapper.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
export default function wrapper(source: string, packages: string[], primate_run: string, id: string
|
|
1
|
+
export default function wrapper(source: string, packages: string[], primate_run: string, id: string, context?: {
|
|
2
|
+
i18n?: any;
|
|
3
|
+
session?: any;
|
|
4
|
+
}): Promise<void>;
|
|
2
5
|
//# sourceMappingURL=wrapper.d.ts.map
|
package/lib/private/wrapper.js
CHANGED
|
@@ -3,7 +3,6 @@ import helpers from "@primate/python/helpers";
|
|
|
3
3
|
import pyodide from "@primate/python/pyodide";
|
|
4
4
|
import to_request from "@primate/python/to-request";
|
|
5
5
|
import to_response from "@primate/python/to-response";
|
|
6
|
-
import session from "primate/config/session";
|
|
7
6
|
import route from "primate/route";
|
|
8
7
|
const messageCallback = () => { };
|
|
9
8
|
let _micropip = null;
|
|
@@ -23,7 +22,33 @@ async function load_package(micropip, pkg) {
|
|
|
23
22
|
await micropip.install(pkg, { messageCallback });
|
|
24
23
|
installed.add(pkg);
|
|
25
24
|
}
|
|
26
|
-
|
|
25
|
+
function wrap_session(session) {
|
|
26
|
+
if (!session)
|
|
27
|
+
return null;
|
|
28
|
+
return {
|
|
29
|
+
get id() { return session.id; },
|
|
30
|
+
get exists() { return session.exists; },
|
|
31
|
+
create(initial) { session.create(borrow(initial)); },
|
|
32
|
+
get() { return session.get(); },
|
|
33
|
+
try_get() { return session.try(); },
|
|
34
|
+
set(data) { session.set(borrow(data)); },
|
|
35
|
+
destroy() { session.destroy(); },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function wrap_i18n(i18n) {
|
|
39
|
+
if (!i18n)
|
|
40
|
+
return null;
|
|
41
|
+
return {
|
|
42
|
+
get locale() { return i18n.locale.get(); },
|
|
43
|
+
t(key, params) {
|
|
44
|
+
if (!params)
|
|
45
|
+
return i18n(key);
|
|
46
|
+
return i18n(key, JSON.parse(params));
|
|
47
|
+
},
|
|
48
|
+
set(locale) { i18n.locale.set(locale); },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export default async function wrapper(source, packages, primate_run, id, context = {}) {
|
|
27
52
|
const python = await pyodide();
|
|
28
53
|
const micropip = await load_micropip(python);
|
|
29
54
|
const route_id = JSON.stringify(id);
|
|
@@ -41,39 +66,19 @@ export default async function wrapper(source, packages, primate_run, id) {
|
|
|
41
66
|
from primate import Route
|
|
42
67
|
list(Route.registry(${route_id}).keys())
|
|
43
68
|
`).toJs();
|
|
44
|
-
const wrapped_session =
|
|
45
|
-
|
|
46
|
-
return session().id;
|
|
47
|
-
},
|
|
48
|
-
get exists() {
|
|
49
|
-
return session().exists;
|
|
50
|
-
},
|
|
51
|
-
create(initial) {
|
|
52
|
-
session().create(borrow(initial));
|
|
53
|
-
},
|
|
54
|
-
get() {
|
|
55
|
-
return session().get();
|
|
56
|
-
},
|
|
57
|
-
try() {
|
|
58
|
-
return session().get();
|
|
59
|
-
},
|
|
60
|
-
set(data) {
|
|
61
|
-
session().set(borrow(data));
|
|
62
|
-
},
|
|
63
|
-
destroy() {
|
|
64
|
-
session().destroy();
|
|
65
|
-
},
|
|
66
|
-
};
|
|
69
|
+
const wrapped_session = wrap_session(context.session);
|
|
70
|
+
const wrapped_i18n = wrap_i18n(context.i18n);
|
|
67
71
|
for (const verb of verbs) {
|
|
68
72
|
route[verb.toLowerCase()](async (request) => {
|
|
69
73
|
python.globals.set("js_req", await to_request(request));
|
|
70
74
|
python.globals.set("helpers_obj", helpers);
|
|
71
75
|
python.globals.set("session_obj", wrapped_session);
|
|
76
|
+
python.globals.set("i18n_obj", wrapped_i18n);
|
|
72
77
|
const verb_str = JSON.stringify(verb);
|
|
73
78
|
try {
|
|
74
79
|
const result = await python.runPythonAsync(`
|
|
75
80
|
from primate import Route
|
|
76
|
-
await Route.call_js(${route_id}, ${verb_str}, js_req, helpers_obj, session_obj)
|
|
81
|
+
await Route.call_js(${route_id}, ${verb_str}, js_req, helpers_obj, session_obj, i18n_obj)
|
|
77
82
|
`);
|
|
78
83
|
return to_response(result);
|
|
79
84
|
}
|
|
@@ -85,6 +90,7 @@ export default async function wrapper(source, packages, primate_run, id) {
|
|
|
85
90
|
python.globals.delete("js_req");
|
|
86
91
|
python.globals.delete("helpers_obj");
|
|
87
92
|
python.globals.delete("session_obj");
|
|
93
|
+
python.globals.delete("i18n_obj");
|
|
88
94
|
}
|
|
89
95
|
});
|
|
90
96
|
}
|
package/lib/public/default.d.ts
CHANGED
package/lib/public/default.js
CHANGED
package/lib/public/runtime.d.ts
CHANGED
package/lib/public/runtime.js
CHANGED
package/package.json
CHANGED
|
@@ -1,35 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/python",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Python backend for Primate",
|
|
5
5
|
"homepage": "https://primate.run/docs/backend/python",
|
|
6
6
|
"bugs": "https://github.com/primate-run/primate/issues",
|
|
7
|
+
"type": "module",
|
|
7
8
|
"license": "MIT",
|
|
8
|
-
"files": [
|
|
9
|
-
"/lib/**/*.js",
|
|
10
|
-
"/lib/**/*.d.ts",
|
|
11
|
-
"!/**/*.spec.*"
|
|
12
|
-
],
|
|
13
9
|
"repository": {
|
|
14
10
|
"type": "git",
|
|
15
11
|
"url": "https://github.com/primate-run/primate",
|
|
16
12
|
"directory": "packages/python"
|
|
17
13
|
},
|
|
14
|
+
"files": [
|
|
15
|
+
"/lib/**/*.js",
|
|
16
|
+
"/lib/**/*.d.ts",
|
|
17
|
+
"!/**/*.spec.*"
|
|
18
|
+
],
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@rcompat/assert": "^0.
|
|
20
|
-
"@rcompat/
|
|
21
|
-
"@rcompat/
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
20
|
+
"@rcompat/assert": "^0.8.1",
|
|
21
|
+
"@rcompat/error": "^0.3.1",
|
|
22
|
+
"@rcompat/fs": "^0.28.1",
|
|
23
|
+
"@rcompat/io": "^0.5.1",
|
|
24
|
+
"pyodide": "^0.29.3",
|
|
25
|
+
"@primate/core": "^0.6.0",
|
|
26
|
+
"pema": "^0.6.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@rcompat/type": "^0.11.1"
|
|
25
30
|
},
|
|
26
31
|
"peerDependencies": {
|
|
27
|
-
"primate": "^0.
|
|
32
|
+
"primate": "^0.37.0"
|
|
28
33
|
},
|
|
29
|
-
"type": "module",
|
|
30
34
|
"imports": {
|
|
31
35
|
"#*": {
|
|
32
|
-
"
|
|
36
|
+
"@primate/source": "./src/private/*.ts",
|
|
33
37
|
"default": "./lib/private/*.js"
|
|
34
38
|
}
|
|
35
39
|
},
|
|
@@ -39,13 +43,14 @@
|
|
|
39
43
|
"default": "./lib/public/default.js"
|
|
40
44
|
},
|
|
41
45
|
"./*": {
|
|
42
|
-
"
|
|
46
|
+
"@primate/source": "./src/public/*.ts",
|
|
43
47
|
"default": "./lib/public/*.js"
|
|
44
48
|
}
|
|
45
49
|
},
|
|
46
50
|
"scripts": {
|
|
47
51
|
"build": "npm run clean && tsc",
|
|
48
52
|
"clean": "rm -rf ./lib",
|
|
49
|
-
"lint": "eslint ."
|
|
53
|
+
"lint": "eslint .",
|
|
54
|
+
"test": "npx proby"
|
|
50
55
|
}
|
|
51
56
|
}
|
package/lib/private/Default.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import Runtime from "#Runtime";
|
|
2
|
-
import type BuildApp from "@primate/core/BuildApp";
|
|
3
|
-
import type NextBuild from "@primate/core/NextBuild";
|
|
4
|
-
export default class Default extends Runtime {
|
|
5
|
-
build(app: BuildApp, next: NextBuild): Promise<BuildApp>;
|
|
6
|
-
}
|
|
7
|
-
//# sourceMappingURL=Default.d.ts.map
|
package/lib/private/Default.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import Runtime from "#Runtime";
|
|
2
|
-
import TAG from "@primate/core/backend/TAG";
|
|
3
|
-
import fail from "@primate/core/fail";
|
|
4
|
-
import log from "@primate/core/log";
|
|
5
|
-
import assert from "@rcompat/assert";
|
|
6
|
-
import FileRef from "@rcompat/fs/FileRef";
|
|
7
|
-
import execute from "@rcompat/stdio/execute";
|
|
8
|
-
const PACKAGE = "primate-run";
|
|
9
|
-
const [MAJOR, MINOR] = TAG.split(".").map(Number);
|
|
10
|
-
function package_not_found() {
|
|
11
|
-
return fail("package not found - run 'pip install {0}~={1}.0'", PACKAGE, TAG);
|
|
12
|
-
}
|
|
13
|
-
function pkg_mismatch(major, minor) {
|
|
14
|
-
return fail("installed {0} package version {1}.{2}.x not in range ~> {3}.x", PACKAGE, major, minor, TAG);
|
|
15
|
-
}
|
|
16
|
-
async function show_package() {
|
|
17
|
-
const str0 = () => "";
|
|
18
|
-
let out = await execute(`pip show ${PACKAGE} 2>/dev/null`).catch(str0);
|
|
19
|
-
if (out.trim())
|
|
20
|
-
return out;
|
|
21
|
-
out = await execute(`uv pip show ${PACKAGE} 2>/dev/null`).catch(str0);
|
|
22
|
-
if (out.trim())
|
|
23
|
-
return out;
|
|
24
|
-
out = await execute(`python -m pip show ${PACKAGE} 2>/dev/null`).catch(str0);
|
|
25
|
-
if (out.trim())
|
|
26
|
-
return out;
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
async function check_version() {
|
|
30
|
-
const output = await show_package();
|
|
31
|
-
if (!output)
|
|
32
|
-
throw package_not_found();
|
|
33
|
-
const version_match = output.match(/Version:\s*(\d+)\.(\d+)\.(\d+)/);
|
|
34
|
-
if (!version_match)
|
|
35
|
-
throw package_not_found();
|
|
36
|
-
const [major, minor] = version_match.slice(1).map(Number);
|
|
37
|
-
if (major !== MAJOR || minor !== MINOR)
|
|
38
|
-
throw pkg_mismatch(major, minor);
|
|
39
|
-
log.info("using {0} package {1}.{2}.x", PACKAGE, major, minor);
|
|
40
|
-
}
|
|
41
|
-
export default class Default extends Runtime {
|
|
42
|
-
async build(app, next) {
|
|
43
|
-
await check_version();
|
|
44
|
-
const requirements_txt = app.root.join("requirements.txt");
|
|
45
|
-
let packages = [];
|
|
46
|
-
if (await requirements_txt.exists()) {
|
|
47
|
-
const requirements = await FileRef.text(requirements_txt);
|
|
48
|
-
packages = requirements
|
|
49
|
-
.split("\n")
|
|
50
|
-
.filter(line => line.trim() && !line.startsWith("#"))
|
|
51
|
-
.map(p => p.trim());
|
|
52
|
-
}
|
|
53
|
-
const packages_str = JSON.stringify(packages);
|
|
54
|
-
app.bind(this.fileExtension, async (file, { context }) => {
|
|
55
|
-
assert(context === "routes", "python: only route files are supported");
|
|
56
|
-
const relative = file.debase(app.path.routes).path.replace(/^\//, "");
|
|
57
|
-
const source = await file.text();
|
|
58
|
-
return `
|
|
59
|
-
import wrapper from "@primate/python/wrapper";
|
|
60
|
-
await wrapper(
|
|
61
|
-
${JSON.stringify(source)},
|
|
62
|
-
${packages_str},
|
|
63
|
-
"${PACKAGE}~=${TAG}.0",
|
|
64
|
-
"${relative}"
|
|
65
|
-
);
|
|
66
|
-
`;
|
|
67
|
-
});
|
|
68
|
-
return next(app);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
//# sourceMappingURL=Default.js.map
|
package/lib/private/Runtime.d.ts
DELETED