Commit 1bd19e3f authored by Michael Droettboom's avatar Michael Droettboom

Ensure that package loading runs in sequence

parent af569129
......@@ -18,6 +18,7 @@ var languagePluginLoader = new Promise((resolve, reject) => {
// Package loading
var packages = undefined;
let loadedPackages = new Array();
var loadPackagePromise = new Promise((resolve) => resolve());
let _uri_to_package_name = (package_uri) => {
// Generate a unique package name from URI
......@@ -33,7 +34,7 @@ var languagePluginLoader = new Promise((resolve, reject) => {
}
};
let loadPackage = (names) => {
let _loadPackage = (names) => {
// DFS to find all dependencies of the requested packages
let packages = window.pyodide.packages.dependencies;
let queue = [].concat(names || []);
......@@ -121,6 +122,13 @@ var languagePluginLoader = new Promise((resolve, reject) => {
return promise;
};
let loadPackage = (names) => {
/* We want to make sure that only one loadPackage invocation runs at any
* given time, so this creates a "chain" of promises. */
loadPackagePromise = loadPackagePromise.then(() => _loadPackage(names));
return loadPackagePromise;
};
function fixRecursionLimit(pyodide) {
// The Javascript/Wasm call stack may be too small to handle the default
// Python call stack limit of 1000 frames. This is generally the case on
......
......@@ -91,12 +91,15 @@ class SeleniumWrapper:
return self.driver.execute_script(catch)
def load_package(self, packages):
from selenium.common.exceptions import TimeoutException
self.run_js(
'window.done = false\n' +
'pyodide.loadPackage({!r})'.format(packages) +
'.then(function() { window.done = true; })')
self.wait_until_packages_loaded()
def wait_until_packages_loaded(self):
from selenium.common.exceptions import TimeoutException
try:
self.wait.until(PackageLoaded())
except TimeoutException as exc:
......
......@@ -44,7 +44,29 @@ def test_load_packages_multiple(selenium_standalone, packages):
selenium.load_package(packages)
selenium.run(f'import {packages[0]}')
selenium.run(f'import {packages[1]}')
# The long must show that each package is loaded exactly once,
# The log must show that each package is loaded exactly once,
# including when one package is a dependency of the other
# ('pyparsing' and 'matplotlib')
assert selenium.logs.count(f'Loading {packages[0]}') == 1
assert selenium.logs.count(f'Loading {packages[1]}') == 1
@pytest.mark.parametrize('packages', [['pyparsing', 'pytz'],
['pyparsing', 'matplotlib']],
ids='-'.join)
def test_load_packages_sequential(selenium_standalone, packages):
selenium = selenium_standalone
promises = ','.join(
'pyodide.loadPackage("{}")'.format(x) for x in packages
)
selenium.run_js(
'window.done = false\n' +
'Promise.all([{}])'.format(promises) +
'.then(function() { window.done = true; })')
selenium.wait_until_packages_loaded()
selenium.run(f'import {packages[0]}')
selenium.run(f'import {packages[1]}')
# The log must show that each package is loaded exactly once,
# including when one package is a dependency of the other
# ('pyparsing' and 'matplotlib')
assert selenium.logs.count(f'Loading {packages[0]}') == 1
......
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