Ensure that package loading runs in sequence

This commit is contained in:
Michael Droettboom 2018-09-06 10:38:32 -04:00
parent af569129fc
commit 1bd19e3fe4
3 changed files with 37 additions and 4 deletions

View File

@ -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

View File

@ -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:

View File

@ -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