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) => { ...@@ -18,6 +18,7 @@ var languagePluginLoader = new Promise((resolve, reject) => {
// Package loading // Package loading
var packages = undefined; var packages = undefined;
let loadedPackages = new Array(); let loadedPackages = new Array();
var loadPackagePromise = new Promise((resolve) => resolve());
let _uri_to_package_name = (package_uri) => { let _uri_to_package_name = (package_uri) => {
// Generate a unique package name from URI // Generate a unique package name from URI
...@@ -33,7 +34,7 @@ var languagePluginLoader = new Promise((resolve, reject) => { ...@@ -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 // DFS to find all dependencies of the requested packages
let packages = window.pyodide.packages.dependencies; let packages = window.pyodide.packages.dependencies;
let queue = [].concat(names || []); let queue = [].concat(names || []);
...@@ -121,6 +122,13 @@ var languagePluginLoader = new Promise((resolve, reject) => { ...@@ -121,6 +122,13 @@ var languagePluginLoader = new Promise((resolve, reject) => {
return promise; 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) { function fixRecursionLimit(pyodide) {
// The Javascript/Wasm call stack may be too small to handle the default // 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 // Python call stack limit of 1000 frames. This is generally the case on
......
...@@ -91,12 +91,15 @@ class SeleniumWrapper: ...@@ -91,12 +91,15 @@ class SeleniumWrapper:
return self.driver.execute_script(catch) return self.driver.execute_script(catch)
def load_package(self, packages): def load_package(self, packages):
from selenium.common.exceptions import TimeoutException
self.run_js( self.run_js(
'window.done = false\n' + 'window.done = false\n' +
'pyodide.loadPackage({!r})'.format(packages) + 'pyodide.loadPackage({!r})'.format(packages) +
'.then(function() { window.done = true; })') '.then(function() { window.done = true; })')
self.wait_until_packages_loaded()
def wait_until_packages_loaded(self):
from selenium.common.exceptions import TimeoutException
try: try:
self.wait.until(PackageLoaded()) self.wait.until(PackageLoaded())
except TimeoutException as exc: except TimeoutException as exc:
......
...@@ -44,7 +44,29 @@ def test_load_packages_multiple(selenium_standalone, packages): ...@@ -44,7 +44,29 @@ def test_load_packages_multiple(selenium_standalone, packages):
selenium.load_package(packages) selenium.load_package(packages)
selenium.run(f'import {packages[0]}') selenium.run(f'import {packages[0]}')
selenium.run(f'import {packages[1]}') 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 # including when one package is a dependency of the other
# ('pyparsing' and 'matplotlib') # ('pyparsing' and 'matplotlib')
assert selenium.logs.count(f'Loading {packages[0]}') == 1 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