Commit 158b85ce authored by Michael Droettboom's avatar Michael Droettboom

Fix #20: Basic modularization of file system.

parent b2599e31
PYODIDE_ROOT=$(abspath .) PYODIDE_ROOT=$(abspath .)
include Makefile.envs include Makefile.envs
FILEPACKAGER=emsdk/emsdk/emscripten/incoming/tools/file_packager.py
PYVERSION=3.6.4 PYVERSION=3.6.4
PYMINOR=$(basename $(PYVERSION)) PYMINOR=$(basename $(PYVERSION))
CPYTHONROOT=cpython CPYTHONROOT=cpython
...@@ -55,7 +57,11 @@ all: build/pyodide.asm.html \ ...@@ -55,7 +57,11 @@ all: build/pyodide.asm.html \
build/pyodide.js \ build/pyodide.js \
build/pyodide_dev.js \ build/pyodide_dev.js \
build/python.html \ build/python.html \
build/renderedhtml.css build/renderedhtml.css \
build/numpy.data \
build/dateutil.data \
build/pytz.data \
build/pandas.data
build/pyodide.asm.html: src/main.bc src/jsimport.bc src/jsproxy.bc src/js2python.bc \ build/pyodide.asm.html: src/main.bc src/jsimport.bc src/jsproxy.bc src/js2python.bc \
...@@ -64,6 +70,9 @@ build/pyodide.asm.html: src/main.bc src/jsimport.bc src/jsproxy.bc src/js2python ...@@ -64,6 +70,9 @@ build/pyodide.asm.html: src/main.bc src/jsimport.bc src/jsproxy.bc src/js2python
[ -d build ] || mkdir build [ -d build ] || mkdir build
$(CC) -s EXPORT_NAME="'pyodide'" --bind -o $@ $(filter %.bc,$^) $(LDFLAGS) \ $(CC) -s EXPORT_NAME="'pyodide'" --bind -o $@ $(filter %.bc,$^) $(LDFLAGS) \
$(foreach d,$(wildcard root/*),--preload-file $d@/$(notdir $d)) $(foreach d,$(wildcard root/*),--preload-file $d@/$(notdir $d))
rm build/pyodide.asm.asm.js
rm build/pyodide.asm.wasm.pre
rm build/pyodide.asm.html
build/pyodide_dev.js: src/pyodide.js build/pyodide_dev.js: src/pyodide.js
...@@ -112,12 +121,25 @@ clean: ...@@ -112,12 +121,25 @@ clean:
$(CC) -o $@ $< $(CFLAGS) $(CC) -o $@ $< $(CFLAGS)
# TODO: It would be nice to generalize this
build/numpy.data: $(NUMPY_LIBS)
python2 $(FILEPACKAGER) build/numpy.data --preload $(NUMPY_ROOT)@/lib/python3.6/site-packages/numpy --js-output=build/numpy.js --export-name=pyodide --exclude \*.wasm.pre --exclude __pycache__
build/dateutil.data: $(DATEUTIL_LIBS)
python2 $(FILEPACKAGER) build/dateutil.data --preload $(DATEUTIL_ROOT)@/lib/python3.6/site-packages/dateutil --js-output=build/dateutil.js --export-name=pyodide --exclude \*.wasm.pre --exclude __pycache__
build/pytz.data: $(PYTZ_LIBS)
python2 $(FILEPACKAGER) build/pytz.data --preload $(PYTZ_ROOT)@/lib/python3.6/site-packages/pytz --js-output=build/pytz.js --export-name=pyodide --exclude \*.wasm.pre --exclude __pycache__
build/pandas.data: $(PANDAS_LIBS)
python2 $(FILEPACKAGER) build/pandas.data --preload $(PANDAS_ROOT)@/lib/python3.6/site-packages/pandas --js-output=build/pandas.js --export-name=pyodide --exclude \*.wasm.pre --exclude __pycache__
root/.built: \ root/.built: \
$(CPYTHONLIB) \ $(CPYTHONLIB) \
$(NUMPY_LIBS) \
$(PANDAS_LIBS) \
$(DATEUTIL_LIBS) \
$(PYTZ_LIBS) \
$(SIX_LIBS) \ $(SIX_LIBS) \
src/lazy_import.py \ src/lazy_import.py \
src/sitecustomize.py \ src/sitecustomize.py \
...@@ -126,12 +148,7 @@ root/.built: \ ...@@ -126,12 +148,7 @@ root/.built: \
rm -rf root rm -rf root
mkdir -p root/lib mkdir -p root/lib
cp -a $(CPYTHONLIB)/ root/lib cp -a $(CPYTHONLIB)/ root/lib
cp -a numpy/build/numpy $(SITEPACKAGES)
cp -a pandas/build/pandas $(SITEPACKAGES)
cp -a $(DATEUTIL_ROOT) $(SITEPACKAGES)
cp -a $(PYTZ_ROOT) $(SITEPACKAGES)
cp $(SIX_LIBS) $(SITEPACKAGES) cp $(SIX_LIBS) $(SITEPACKAGES)
rm -fr $(SITEPACKAGES)/numpy/distutils
cp src/lazy_import.py $(SITEPACKAGES) cp src/lazy_import.py $(SITEPACKAGES)
cp src/sitecustomize.py $(SITEPACKAGES) cp src/sitecustomize.py $(SITEPACKAGES)
cp src/webbrowser.py root/lib/python$(PYMINOR) cp src/webbrowser.py root/lib/python$(PYMINOR)
......
var languagePluginLoader = new Promise((resolve, reject) => { var languagePluginLoader = new Promise((resolve, reject) => {
let baseURL = "{{DEPLOY}}"; const baseURL = '{{DEPLOY}}';
const packages = {
'dateutil': [],
'numpy': [],
'pandas': ['numpy', 'dateutil', 'pytz'],
'pytz': [],
};
let loadedPackages = new Set();
let loadPackage = (names) => {
if (Array.isArray(names)) {
names = [names];
}
// DFS to find all dependencies of the requested packages
let queue = new Array(names);
let toLoad = new Set();
while (queue.length) {
const package = queue.pop();
if (!packages.hasOwnProperty(package)) {
throw `Unknown package '${package}'`;
}
if (!loadedPackages.has(package)) {
toLoad.add(package);
packages[package].forEach((subpackage) => {
if (!loadedPackages.has(subpackage) &&
!toLoad.has(subpackage)) {
queue.push(subpackage);
}
});
}
}
let promise = new Promise((resolve, reject) => {
var n = toLoad.size;
if (n === 0) {
resolve('No new packages to load');
}
toLoad.forEach((package) => {
let script = document.createElement('script');
script.src = `${baseURL}${package}.js`;
console.log(script.src);
script.onload = (e) => {
n--;
loadedPackages.add(package);
if (n <= 0) {
// All of the requested packages are now loaded.
// We have to invalidate Python's import caches, or it won't
// see the new files.
window.pyodide.runPython(
'import importlib as _importlib\n' +
'_importlib.invalidate_caches()\n');
const packageList = Array.from(toLoad.keys()).join(', ');
resolve(`Loaded ${packageList}`);
}
};
script.onerror = (e) => {
reject(e);
};
document.body.appendChild(script);
});
});
return promise;
};
let wasmURL = `${baseURL}pyodide.asm.wasm`; let wasmURL = `${baseURL}pyodide.asm.wasm`;
let Module = {}; let Module = {};
...@@ -19,6 +86,9 @@ var languagePluginLoader = new Promise((resolve, reject) => { ...@@ -19,6 +86,9 @@ var languagePluginLoader = new Promise((resolve, reject) => {
script.src = `${baseURL}pyodide.asm.js`; script.src = `${baseURL}pyodide.asm.js`;
script.onload = () => { script.onload = () => {
window.pyodide = pyodide(Module); window.pyodide = pyodide(Module);
if (window.iodide !== undefined) {
window.pyodide.loadPackage = loadPackage;
}
}; };
document.body.appendChild(script); document.body.appendChild(script);
......
...@@ -44,6 +44,8 @@ Pyodide adds support for Python in an Iodide notebook, running inside your brows ...@@ -44,6 +44,8 @@ Pyodide adds support for Python in an Iodide notebook, running inside your brows
(A major shortcoming is that `print` from Python currently prints to the Javascript debugger console, rather than to the notebook cell, so some of these examples are more contrived than they need to be.) (A major shortcoming is that `print` from Python currently prints to the Javascript debugger console, rather than to the notebook cell, so some of these examples are more contrived than they need to be.)
**Also to note: If you have any issues, try disabling any ad or tracking blockers for this site.**
First, let's use a plugin cell to load the Python interpreter and tell Iodide about the new cell type. First, let's use a plugin cell to load the Python interpreter and tell Iodide about the new cell type.
%% plugin %% plugin
...@@ -215,7 +217,14 @@ document.getElementById("targetDiv").setAttribute("style", "background-color: re ...@@ -215,7 +217,14 @@ document.getElementById("targetDiv").setAttribute("style", "background-color: re
You bet, [Numpy](http://numpy.org) works. You bet, [Numpy](http://numpy.org) works.
(Except the `numpy.fft` module -- we're working on that, but you can get a lot done without it in a lot of use cases...) To save on download times, isn't loaded by default. We need to manually use
the `pyodide.loadPackage` function from a Javascript cell.
%% js
pyodide.loadPackage('numpy')
%% md
Now that the Numpy package has been loaded (i.e. transferred to your local browser), we can import it:
%% code {"language":"py"} %% code {"language":"py"}
import numpy as np import numpy as np
......
import lazy_import
print("Setting up lazy importing...")
lazy_import.lazy_module("numpy.linalg")
lazy_import.lazy_module("numpy.fft")
lazy_import.lazy_module("numpy.polynomial")
lazy_import.lazy_module("numpy.random")
lazy_import.lazy_module("numpy.ctypeslib")
import sys import sys
sys.argv = ['pyodide'] sys.argv = ['pyodide']
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment