Skip to content

Instantly share code, notes, and snippets.

@sneakers-the-rat
Created March 9, 2024 06:58
Show Gist options
  • Save sneakers-the-rat/fc1387f9e90c7e5f6eaa4dc8f21b8407 to your computer and use it in GitHub Desktop.
Save sneakers-the-rat/fc1387f9e90c7e5f6eaa4dc8f21b8407 to your computer and use it in GitHub Desktop.
LinkML Pydanticgen in the browser with Pyodide
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/styles/default.min.css">
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js"></script>
<!-- and it's easy to individually load additional languages -->
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/languages/python.min.js"></script>
<script src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/languages/yaml.min.js"></script>
</head>
<body>
<div id="boxes" style="display: flex; flex-direction: row; width: 100%; align-items: stretch; position:absolute; height: 100%;">
<div id="schemabox" style="width: 100%; flex-grow:1; padding: 1em; display: flex; flex-direction:column;">
<p>Schema:</p>
<textarea id="code" class="language-yaml" style="width: 100%; flex-grow: 1;">
id: https://w3id.org/linkml/examples/pyodide
name: pyodide
description: |-
Oh look its linkml in the browser
license: https://creativecommons.org/publicdomain/zero/1.0/
default_curi_maps:
- semweb_context
imports:
- linkml:types
default_prefix: pyodide
default_range: string
classes:
Lol:
description: laughing out loud
slots:
- id
- name
- websites
Lmao:
description: |-
An additional indication of laughter
relating to the ass becoming displaced.
slots:
- place
- ass
- last_seen
slots:
id:
identifier: true
name:
websites:
multivalued: true
place:
ass:
range: boolean
last_seen:
any_of:
- range: date
- range: datetime
multivalued: true
</textarea>
</div>
<div id="outputbox" style="width: 100%; flex-grow:1; padding: 1em; display: flex; flex-direction: column;">
<p>Output:</p>
<pre style="width: 100%; flex-grow:1;" disabled><code class="language-python" id="output"></code></textarea>
</div>
<div id="consolebox" style="width: 100%; flex-grow:1; padding: 1em; display: flex; flex-direction: column;">
<p>Console:</p>
<textarea id="console-input" style="width: 100%; flex-grow: 1;"></textarea>
<textarea id="console-output" id="console-input" style="width: 100%; flex-grow: 5;" disabled></textarea>
</div>
</div>
<script>
const output = document.getElementById("output");
const code = document.getElementById("code");
const consoleinput = document.getElementById("console-input");
const consoleoutput = document.getElementById("console-output");
function addToOutput(s) {
// output.value += ">>>" + code.value + "\n" + s + "\n";
output.innerHTML += "\n" + s;
}
output.value = "Initializing...\n";
// init Pyodide
async function main() {
let pyodide = await loadPyodide();
await pyodide.loadPackage("micropip");
const micropip = pyodide.pyimport("micropip");
let packages = [
"linkml",
"linkml_runtime",
"rdflib",
"isodate",
"six",
"prefixcommons",
"requests",
"prefixmaps",
"curies",
"pydantic",
"https://hackers.piracy.solutions/PyTrie-0.4.0-py3-none-any.whl",
"sortedcontainers",
"pyyaml",
"deprecated",
"wrapt",
"jsonasobj2",
"hbreader",
"ssl",
"jinja2",
"json_flattener",
"python-dateutil",
"jsonasobj",
"click",
"ShExJSG",
"pyjsg",
"sqlalchemy"
]
addToOutput('Installing packages...')
for await (const package of packages) {
await micropip.install(package, keep_going = true, deps = false);
addToOutput('Installed: ' + package);
}
let initial_load = pyodide.runPython(`
from linkml.generators.pydanticgen import PydanticGenerator
from linkml_runtime.loaders.yaml_loader import YAMLLoader
from linkml_runtime.linkml_model import SchemaDefinition
`)
addToOutput(initial_load)
async function evaluateSchema() {
output.value = "generating..."
try{
let generated = pyodide.runPython(`
sch = YAMLLoader().load_any(target_class=SchemaDefinition, source="""${code.value}""")
gen = PydanticGenerator(sch)
gen.serialize()
`)
pyodide.runPython(generated);
output.removeAttribute('data-highlighted');
output.innerHTML = generated
} catch (err) {
output.value = err;
}
hljs.highlightAll();
}
async function evaluateConsole(){
try {
consoleinput.disabled = true;
let output = pyodide.runPython(consoleinput.value);
addToConsole(output);
consoleinput.value = "";
} catch (err) {
addToConsole(err);
}
consoleinput.disabled = false;
}
function addToConsole(s) {
consoleoutput.value += ">>>" + consoleinput.value + "\n" + s + "\n";
}
await evaluateSchema();
code.addEventListener('input', evaluateSchema);
consoleinput.addEventListener('keypress', (event) => {
if (event.key === "Enter" && !event.shiftKey){
event.preventDefault();
evaluateConsole()
}
})
return pyodide;
}
let pyodideReadyPromise = main();
</script>
</body>
</html>
@sneakers-the-rat
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment