An easy-to-use platform for EEG experimentation in the classroom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

direct copy from pyodide-0.10 build

this adds the original pyodide.js with no mods. doesn't work out of the box. gitignore src files for building. the good place if we need to remove from git history if better solution come for importing

+406
+2
.gitignore
··· 49 49 *.sass.d.ts 50 50 *.scss.d.ts 51 51 keys.js 52 + 53 + app/utils/pyodide/src
+404
app/utils/pyodide/pyodide.js
··· 1 + /** 2 + * The main bootstrap script for loading pyodide. 3 + */ 4 + 5 + var languagePluginLoader = new Promise((resolve, reject) => { 6 + // This is filled in by the Makefile to be either a local file or the 7 + // deployed location. TODO: This should be done in a less hacky 8 + // way. 9 + var baseURL = self.languagePluginUrl || 'https://iodide.io/pyodide-demo/'; 10 + baseURL = baseURL.substr(0, baseURL.lastIndexOf('/')) + '/'; 11 + 12 + //////////////////////////////////////////////////////////// 13 + // Package loading 14 + let loadedPackages = new Array(); 15 + var loadPackagePromise = new Promise((resolve) => resolve()); 16 + // Regexp for validating package name and URI 17 + var package_name_regexp = '[a-z0-9_][a-z0-9_\-]*' 18 + var package_uri_regexp = 19 + new RegExp('^https?://.*?(' + package_name_regexp + ').js$', 'i'); 20 + var package_name_regexp = new RegExp('^' + package_name_regexp + '$', 'i'); 21 + 22 + let _uri_to_package_name = (package_uri) => { 23 + // Generate a unique package name from URI 24 + 25 + if (package_name_regexp.test(package_uri)) { 26 + return package_uri; 27 + } else if (package_uri_regexp.test(package_uri)) { 28 + let match = package_uri_regexp.exec(package_uri); 29 + // Get the regexp group corresponding to the package name 30 + return match[1]; 31 + } else { 32 + return null; 33 + } 34 + }; 35 + 36 + // clang-format off 37 + let preloadWasm = () => { 38 + // On Chrome, we have to instantiate wasm asynchronously. Since that 39 + // can't be done synchronously within the call to dlopen, we instantiate 40 + // every .so that comes our way up front, caching it in the 41 + // `preloadedWasm` dictionary. 42 + 43 + let promise = new Promise((resolve) => resolve()); 44 + let FS = pyodide._module.FS; 45 + 46 + function recurseDir(rootpath) { 47 + let dirs; 48 + try { 49 + dirs = FS.readdir(rootpath); 50 + } catch { 51 + return; 52 + } 53 + for (let entry of dirs) { 54 + if (entry.startsWith('.')) { 55 + continue; 56 + } 57 + const path = rootpath + entry; 58 + if (entry.endsWith('.so')) { 59 + if (Module['preloadedWasm'][path] === undefined) { 60 + promise = promise 61 + .then(() => Module['loadWebAssemblyModule']( 62 + FS.readFile(path), {loadAsync: true})) 63 + .then((module) => { 64 + Module['preloadedWasm'][path] = module; 65 + }); 66 + } 67 + } else if (FS.isDir(FS.lookupPath(path).node.mode)) { 68 + recurseDir(path + '/'); 69 + } 70 + } 71 + } 72 + 73 + recurseDir('/'); 74 + 75 + return promise; 76 + } 77 + // clang-format on 78 + 79 + function loadScript(url, onload, onerror) { 80 + if (self.document) { // browser 81 + const script = self.document.createElement('script'); 82 + script.src = url; 83 + script.onload = (e) => { onload(); }; 84 + script.onerror = (e) => { onerror(); }; 85 + self.document.head.appendChild(script); 86 + } else if (self.importScripts) { // webworker 87 + try { 88 + self.importScripts(url); 89 + onload(); 90 + } catch { 91 + onerror(); 92 + } 93 + } 94 + } 95 + 96 + let _loadPackage = (names, messageCallback) => { 97 + // DFS to find all dependencies of the requested packages 98 + let packages = self.pyodide._module.packages.dependencies; 99 + let loadedPackages = self.pyodide.loadedPackages; 100 + let queue = [].concat(names || []); 101 + let toLoad = new Array(); 102 + while (queue.length) { 103 + let package_uri = queue.pop(); 104 + 105 + const package = _uri_to_package_name(package_uri); 106 + 107 + if (package == null) { 108 + console.error(`Invalid package name or URI '${package_uri}'`); 109 + return; 110 + } else if (package == package_uri) { 111 + package_uri = 'default channel'; 112 + } 113 + 114 + if (package in loadedPackages) { 115 + if (package_uri != loadedPackages[package]) { 116 + console.error(`URI mismatch, attempting to load package ` + 117 + `${package} from ${package_uri} while it is already ` + 118 + `loaded from ${loadedPackages[package]}!`); 119 + return; 120 + } 121 + } else if (package in toLoad) { 122 + if (package_uri != toLoad[package]) { 123 + console.error(`URI mismatch, attempting to load package ` + 124 + `${package} from ${package_uri} while it is already ` + 125 + `being loaded from ${toLoad[package]}!`); 126 + return; 127 + } 128 + } else { 129 + console.log(`Loading ${package} from ${package_uri}`); 130 + 131 + toLoad[package] = package_uri; 132 + if (packages.hasOwnProperty(package)) { 133 + packages[package].forEach((subpackage) => { 134 + if (!(subpackage in loadedPackages) && !(subpackage in toLoad)) { 135 + queue.push(subpackage); 136 + } 137 + }); 138 + } else { 139 + console.error(`Unknown package '${package}'`); 140 + } 141 + } 142 + } 143 + 144 + self.pyodide._module.locateFile = (path) => { 145 + // handle packages loaded from custom URLs 146 + let package = path.replace(/\.data$/, ""); 147 + if (package in toLoad) { 148 + let package_uri = toLoad[package]; 149 + if (package_uri != 'default channel') { 150 + return package_uri.replace(/\.js$/, ".data"); 151 + }; 152 + }; 153 + return baseURL + path; 154 + }; 155 + 156 + let promise = new Promise((resolve, reject) => { 157 + if (Object.keys(toLoad).length === 0) { 158 + resolve('No new packages to load'); 159 + return; 160 + } 161 + 162 + const packageList = Array.from(Object.keys(toLoad)).join(', '); 163 + if (messageCallback !== undefined) { 164 + messageCallback(`Loading ${packageList}`); 165 + } 166 + 167 + // monitorRunDependencies is called at the beginning and the end of each 168 + // package being loaded. We know we are done when it has been called 169 + // exactly "toLoad * 2" times. 170 + var packageCounter = Object.keys(toLoad).length * 2; 171 + 172 + self.pyodide._module.monitorRunDependencies = () => { 173 + packageCounter--; 174 + if (packageCounter === 0) { 175 + for (let package in toLoad) { 176 + self.pyodide.loadedPackages[package] = toLoad[package]; 177 + } 178 + delete self.pyodide._module.monitorRunDependencies; 179 + self.removeEventListener('error', windowErrorHandler); 180 + if (!isFirefox) { 181 + preloadWasm().then(() => {resolve(`Loaded ${packageList}`)}); 182 + } else { 183 + resolve(`Loaded ${packageList}`); 184 + } 185 + } 186 + }; 187 + 188 + // Add a handler for any exceptions that are thrown in the process of 189 + // loading a package 190 + var windowErrorHandler = (err) => { 191 + delete self.pyodide._module.monitorRunDependencies; 192 + self.removeEventListener('error', windowErrorHandler); 193 + // Set up a new Promise chain, since this one failed 194 + loadPackagePromise = new Promise((resolve) => resolve()); 195 + reject(err.message); 196 + }; 197 + self.addEventListener('error', windowErrorHandler); 198 + 199 + for (let package in toLoad) { 200 + let scriptSrc; 201 + let package_uri = toLoad[package]; 202 + if (package_uri == 'default channel') { 203 + scriptSrc = `${baseURL}${package}.js`; 204 + } else { 205 + scriptSrc = `${package_uri}`; 206 + } 207 + loadScript(scriptSrc, () => {}, () => { 208 + // If the package_uri fails to load, call monitorRunDependencies twice 209 + // (so packageCounter will still hit 0 and finish loading), and remove 210 + // the package from toLoad so we don't mark it as loaded. 211 + console.error(`Couldn't load package from URL ${scriptSrc}`) 212 + let index = toLoad.indexOf(package); 213 + if (index !== -1) { 214 + toLoad.splice(index, 1); 215 + } 216 + for (let i = 0; i < 2; i++) { 217 + self.pyodide._module.monitorRunDependencies(); 218 + } 219 + }); 220 + } 221 + 222 + // We have to invalidate Python's import caches, or it won't 223 + // see the new files. This is done here so it happens in parallel 224 + // with the fetching over the network. 225 + self.pyodide.runPython('import importlib as _importlib\n' + 226 + '_importlib.invalidate_caches()\n'); 227 + }); 228 + 229 + return promise; 230 + }; 231 + 232 + let loadPackage = (names, messageCallback) => { 233 + /* We want to make sure that only one loadPackage invocation runs at any 234 + * given time, so this creates a "chain" of promises. */ 235 + loadPackagePromise = 236 + loadPackagePromise.then(() => _loadPackage(names, messageCallback)); 237 + return loadPackagePromise; 238 + }; 239 + 240 + //////////////////////////////////////////////////////////// 241 + // Fix Python recursion limit 242 + function fixRecursionLimit(pyodide) { 243 + // The Javascript/Wasm call stack may be too small to handle the default 244 + // Python call stack limit of 1000 frames. This is generally the case on 245 + // Chrom(ium), but not on Firefox. Here, we determine the Javascript call 246 + // stack depth available, and then divide by 50 (determined heuristically) 247 + // to set the maximum Python call stack depth. 248 + 249 + let depth = 0; 250 + function recurse() { 251 + depth += 1; 252 + recurse(); 253 + } 254 + try { 255 + recurse(); 256 + } catch (err) { 257 + ; 258 + } 259 + 260 + let recursionLimit = depth / 50; 261 + if (recursionLimit > 1000) { 262 + recursionLimit = 1000; 263 + } 264 + pyodide.runPython( 265 + `import sys; sys.setrecursionlimit(int(${recursionLimit}))`); 266 + }; 267 + 268 + //////////////////////////////////////////////////////////// 269 + // Rearrange namespace for public API 270 + let PUBLIC_API = [ 271 + 'globals', 272 + 'loadPackage', 273 + 'loadedPackages', 274 + 'pyimport', 275 + 'repr', 276 + 'runPython', 277 + 'runPythonAsync', 278 + 'checkABI', 279 + 'version', 280 + ]; 281 + 282 + function makePublicAPI(module, public_api) { 283 + var namespace = {_module : module}; 284 + for (let name of public_api) { 285 + namespace[name] = module[name]; 286 + } 287 + return namespace; 288 + } 289 + 290 + //////////////////////////////////////////////////////////// 291 + // Loading Pyodide 292 + let wasmURL = `${baseURL}pyodide.asm.wasm`; 293 + let Module = {}; 294 + self.Module = Module; 295 + 296 + Module.noImageDecoding = true; 297 + Module.noAudioDecoding = true; 298 + Module.noWasmDecoding = true; 299 + Module.preloadedWasm = {}; 300 + let isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; 301 + 302 + let wasm_promise = WebAssembly.compileStreaming(fetch(wasmURL)); 303 + Module.instantiateWasm = (info, receiveInstance) => { 304 + wasm_promise.then(module => WebAssembly.instantiate(module, info)) 305 + .then(instance => receiveInstance(instance)); 306 + return {}; 307 + }; 308 + 309 + Module.checkABI = function(ABI_number) { 310 + if (ABI_number !== parseInt('1')) { 311 + var ABI_mismatch_exception = 312 + `ABI numbers differ. Expected 1, got ${ABI_number}`; 313 + console.error(ABI_mismatch_exception); 314 + throw ABI_mismatch_exception; 315 + } 316 + return true; 317 + }; 318 + 319 + Module.locateFile = (path) => baseURL + path; 320 + var postRunPromise = new Promise((resolve, reject) => { 321 + Module.postRun = () => { 322 + delete self.Module; 323 + fetch(`${baseURL}packages.json`) 324 + .then((response) => response.json()) 325 + .then((json) => { 326 + fixRecursionLimit(self.pyodide); 327 + self.pyodide.globals = 328 + self.pyodide.runPython('import sys\nsys.modules["__main__"]'); 329 + self.pyodide = makePublicAPI(self.pyodide, PUBLIC_API); 330 + self.pyodide._module.packages = json; 331 + resolve(); 332 + }); 333 + }; 334 + }); 335 + 336 + var dataLoadPromise = new Promise((resolve, reject) => { 337 + Module.monitorRunDependencies = 338 + (n) => { 339 + if (n === 0) { 340 + delete Module.monitorRunDependencies; 341 + resolve(); 342 + } 343 + } 344 + }); 345 + 346 + Promise.all([ postRunPromise, dataLoadPromise ]).then(() => resolve()); 347 + 348 + const data_script_src = `${baseURL}pyodide.asm.data.js`; 349 + loadScript(data_script_src, () => { 350 + const scriptSrc = `${baseURL}pyodide.asm.js`; 351 + loadScript(scriptSrc, () => { 352 + // The emscripten module needs to be at this location for the core 353 + // filesystem to install itself. Once that's complete, it will be replaced 354 + // by the call to `makePublicAPI` with a more limited public API. 355 + self.pyodide = pyodide(Module); 356 + self.pyodide.loadedPackages = new Array(); 357 + self.pyodide.loadPackage = loadPackage; 358 + }, () => {}); 359 + }, () => {}); 360 + 361 + //////////////////////////////////////////////////////////// 362 + // Iodide-specific functionality, that doesn't make sense 363 + // if not using with Iodide. 364 + if (self.iodide !== undefined) { 365 + // Load the custom CSS for Pyodide 366 + let link = document.createElement('link'); 367 + link.rel = 'stylesheet'; 368 + link.type = 'text/css'; 369 + link.href = `${baseURL}renderedhtml.css`; 370 + document.getElementsByTagName('head')[0].appendChild(link); 371 + 372 + // Add a custom output handler for Python objects 373 + self.iodide.addOutputRenderer({ 374 + shouldRender : (val) => { 375 + return (typeof val === 'function' && 376 + pyodide._module.PyProxy.isPyProxy(val)); 377 + }, 378 + 379 + render : (val) => { 380 + let div = document.createElement('div'); 381 + div.className = 'rendered_html'; 382 + var element; 383 + if (val._repr_html_ !== undefined) { 384 + let result = val._repr_html_(); 385 + if (typeof result === 'string') { 386 + div.appendChild(new DOMParser() 387 + .parseFromString(result, 'text/html') 388 + .body.firstChild); 389 + element = div; 390 + } else { 391 + element = result; 392 + } 393 + } else { 394 + let pre = document.createElement('pre'); 395 + pre.textContent = val.toString(); 396 + div.appendChild(pre); 397 + element = div; 398 + } 399 + return element.outerHTML; 400 + } 401 + }); 402 + } 403 + }); 404 + languagePluginLoader