Repository: pyodide/pyodide

Issue:
Version selection for packages availble both on PyPi and in Pyodide
For packages not built in pyodide, version selection works as expected. For instance,
```py
>>> import micropip
>>> micropip.install('idna==2.9')   # version before last on PyPi, package not in pyodide
Installed idna
>>> import idna
>>> idna.__version__
2.9
```

However, when one specifies the version for a package available in the pyodide distribution, it is ignored and the version from pyodide is installed regardless if PyPi includes the requested version,
```py
>>> import micropip
>>> micropip.install('pytz==2020.1')
Installed pytz
>>> import pytz
>>> pytz.__version__
2019.3
```


Discussion:
Another manifestation of this bug, is when installing a package from a URL, it would still ignore the URL and load the package from pyodide if it's available there,
```py
>>> import micropip
>>> micropip.install('https://files.pythonhosted.org/packages/4f/a4/879454d49688e2fad93e59d7d4efda580b783c745fd2ec2a3adf87b0808d/pytz-2020.1-py2.py3-none-any.whl')
Installed pytz
>>> import pytz
>>> pytz.__version__
2019.3
```

Resolving patch:
diff --git a/packages/micropip/micropip/micropip.py b/packages/micropip/micropip/micropip.py
--- a/packages/micropip/micropip/micropip.py
+++ b/packages/micropip/micropip/micropip.py
@@ -57,6 +57,14 @@ async def gather(*coroutines):  # type: ignore
         return result
 
 
+if IN_BROWSER:
+    from pyodide_js import loadedPackages
+else:
+
+    class loadedPackages:  # type: ignore
+        pass
+
+
 async def _get_pypi_json(pkgname):
     url = f"https://pypi.org/pypi/{pkgname}/json"
     fd = await _get_url(url)
@@ -112,6 +120,7 @@ async def _install_wheel(name, fileinfo):
     wheel = await _get_url(url)
     _validate_wheel(wheel, fileinfo)
     _extract_wheel(wheel)
+    setattr(loadedPackages, name, url)
 
 
 class _PackageManager:
@@ -155,14 +164,15 @@ async def install(self, requirements: Union[str, List[str]], ctx=None):
             # Note: branch never happens in out-of-browser testing because we
             # report that all dependencies are empty.
             self.installed_packages.update(dict((k, None) for k in pyodide_packages))
-            wheel_promises.append(pyodide_js.loadPackage(list(pyodide_packages)))
+            wheel_promises.append(
+                asyncio.ensure_future(pyodide_js.loadPackage(list(pyodide_packages)))
+            )
 
         # Now install PyPI packages
         for name, wheel, ver in transaction["wheels"]:
             wheel_promises.append(_install_wheel(name, wheel))
             self.installed_packages[name] = ver
         await gather(*wheel_promises)
-        return f'Installed {", ".join(self.installed_packages.keys())}'
 
     async def add_requirement(self, requirement: str, ctx, transaction):
         if requirement.endswith(".whl"):
@@ -245,8 +255,8 @@ def install(requirements: Union[str, List[str]]):
     ----------
     requirements : ``str | List[str]``
 
-        A requirement or list of requirements to install. Each requirement is a string, which should be either
-        a package name or URL to a wheel:
+        A requirement or list of requirements to install. Each requirement is a
+        string, which should be either a package name or URL to a wheel:
 
         - If the requirement ends in ``.whl`` it will be interpreted as a URL.
           The file must be a wheel named in compliance with the
@@ -260,8 +270,8 @@ def install(requirements: Union[str, List[str]]):
     -------
     ``Future``
 
-        A ``Future`` that resolves to ``None`` when all packages have
-        been downloaded and installed.
+        A ``Future`` that resolves to ``None`` when all packages have been
+        downloaded and installed.
     """
     importlib.invalidate_caches()
     return asyncio.ensure_future(PACKAGE_MANAGER.install(requirements))


Test patch:
diff --git a/packages/micropip/test_micropip.py b/packages/micropip/test_micropip.py
--- a/packages/micropip/test_micropip.py
+++ b/packages/micropip/test_micropip.py
@@ -170,3 +170,25 @@ def __init__(self, **entries):
     wheel, ver = micropip.PACKAGE_MANAGER.find_wheel(metadata, requirement)
 
     assert ver == "0.15.5"
+
+
+def test_install_different_version(selenium_standalone_micropip):
+    selenium = selenium_standalone_micropip
+    selenium.run_js(
+        """
+        await pyodide.runPythonAsync(`
+            import micropip
+            await micropip.install(
+                "https://files.pythonhosted.org/packages/89/06/2c2d3034b4d6bf22f2a4ae546d16925898658a33b4400cfb7e2c1e2871a3/pytz-2020.5-py2.py3-none-any.whl"
+            );
+        `);
+        """
+    )
+    selenium.run_js(
+        """
+        pyodide.runPython(`
+            import pytz
+            assert pytz.__version__ == "2020.5"
+        `);
+        """
+    )