Skip to content

Commit 89a7f0d

Browse files
committed
Some refactorings
1 parent 85e2415 commit 89a7f0d

3 files changed

Lines changed: 92 additions & 61 deletions

File tree

micropip/_commands/install.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from packaging.markers import default_environment
66

77
from .._compat import loadPackage, to_js
8+
from .._uninstall import _uninstall
89
from ..constants import FAQ_URLS
910
from ..transaction import Transaction
10-
from .uninstall import uninstall
1111

1212

1313
async def install(
@@ -128,7 +128,14 @@ async def install(
128128
[pkg.name for pkg in transaction.pyodide_packages]
129129
)
130130

131-
uninstall(packages_all, ignore_missing=True)
131+
distributions = []
132+
for pkg_name in packages_all:
133+
try:
134+
distributions.append(importlib.metadata.distribution(pkg_name))
135+
except importlib.metadata.PackageNotFoundError:
136+
pass
137+
138+
_uninstall(distributions)
132139

133140
wheel_promises = []
134141
# Install built-in packages

micropip/_commands/uninstall.py

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
from collections.abc import Iterable
55
from importlib.metadata import Distribution
66

7-
from .._compat import loadedPackages
8-
from .._utils import get_files_in_distribution, get_root
7+
from .._uninstall import _uninstall
98

109

11-
def uninstall(packages: str | Iterable[str], *, ignore_missing: bool = False) -> None:
10+
def uninstall(packages: str | Iterable[str]) -> None:
1211
"""Uninstall the given packages.
1312
1413
This function only supports uninstalling packages that are installed
@@ -23,9 +22,6 @@ def uninstall(packages: str | Iterable[str], *, ignore_missing: bool = False) ->
2322
----------
2423
packages
2524
Packages to uninstall.
26-
27-
_ignore_missing
28-
If ``True``, suppress warnings when a package is not installed.
2925
"""
3026

3127
if isinstance(packages, str):
@@ -37,61 +33,11 @@ def uninstall(packages: str | Iterable[str], *, ignore_missing: bool = False) ->
3733
dist = importlib.metadata.distribution(package)
3834
distributions.append(dist)
3935
except importlib.metadata.PackageNotFoundError:
40-
if not ignore_missing: # TODO: Can we utilize log level here?
41-
warnings.warn(
42-
f"WARNING: Skipping '{package}' as it is not installed.",
43-
stacklevel=1,
44-
)
45-
46-
for dist in distributions:
47-
# Note: this value needs to be retrieved before removing files, as
48-
# dist.name uses metadata file to get the name
49-
name = dist.name
50-
51-
root = get_root(dist)
52-
files = get_files_in_distribution(dist)
53-
directories = set()
54-
55-
for file in files:
56-
if not file.is_file():
57-
if not file.is_relative_to(root):
58-
# This file is not in the site-packages directory. Probably one of:
59-
# - data_files
60-
# - scripts
61-
# - entry_points
62-
# Since we don't support these, we can ignore them (except for data_files (TODO))
63-
continue
64-
65-
warnings.warn(
66-
f"WARNING: A file '{file}' listed in the metadata of '{dist.name}' does not exist.",
67-
stacklevel=1,
68-
)
69-
70-
continue
71-
72-
file.unlink()
73-
74-
if file.parent != root:
75-
directories.add(file.parent)
76-
77-
# Remove directories in reverse hierarchical order
78-
for directory in sorted(directories, key=lambda x: len(x.parts), reverse=True):
79-
try:
80-
directory.rmdir()
81-
except OSError:
82-
warnings.warn(
83-
f"WARNING: A directory '{directory}' is not empty after uninstallation of '{name}'. "
84-
"This might cause problems when installing a new version of the package. ",
85-
stacklevel=1,
86-
)
87-
88-
if hasattr(loadedPackages, name):
89-
delattr(loadedPackages, name)
90-
else:
91-
# This should not happen, but just in case
9236
warnings.warn(
93-
f"WARNING: a package '{name}' was not found in loadedPackages.",
37+
f"WARNING: Skipping '{package}' as it is not installed.",
9438
stacklevel=1,
9539
)
9640

41+
_uninstall(distributions)
42+
9743
importlib.invalidate_caches()

micropip/_uninstall.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import importlib
2+
import importlib.metadata
3+
import warnings
4+
from collections.abc import Iterable
5+
from importlib.metadata import Distribution
6+
7+
from .._compat import loadedPackages
8+
from .._utils import get_files_in_distribution, get_root
9+
10+
11+
def _uninstall(distributions: Iterable[Distribution]) -> None:
12+
"""Uninstall the given package distributions.
13+
14+
This function does not do any checks, so make sure that the distributions
15+
are installed and that they are installed using a wheel file, i.e. packages
16+
that have distribution metadata.
17+
18+
This function also does not invalidate the import cache, so make sure to
19+
call `importlib.invalidate_caches()` after calling this function.
20+
21+
Parameters
22+
----------
23+
distributions
24+
Package distributions to uninstall.
25+
"""
26+
27+
for dist in distributions:
28+
# Note: this value needs to be retrieved before removing files, as
29+
# dist.name uses metadata file to get the name
30+
name = dist.name
31+
32+
root = get_root(dist)
33+
files = get_files_in_distribution(dist)
34+
directories = set()
35+
36+
for file in files:
37+
if not file.is_file():
38+
if not file.is_relative_to(root):
39+
# This file is not in the site-packages directory. Probably one of:
40+
# - data_files
41+
# - scripts
42+
# - entry_points
43+
# Since we don't support these, we can ignore them (except for data_files (TODO))
44+
continue
45+
46+
warnings.warn(
47+
f"WARNING: A file '{file}' listed in the metadata of '{dist.name}' does not exist.",
48+
stacklevel=1,
49+
)
50+
51+
continue
52+
53+
file.unlink()
54+
55+
if file.parent != root:
56+
directories.add(file.parent)
57+
58+
# Remove directories in reverse hierarchical order
59+
for directory in sorted(directories, key=lambda x: len(x.parts), reverse=True):
60+
try:
61+
directory.rmdir()
62+
except OSError:
63+
warnings.warn(
64+
f"WARNING: A directory '{directory}' is not empty after uninstallation of '{name}'. "
65+
"This might cause problems when installing a new version of the package. ",
66+
stacklevel=1,
67+
)
68+
69+
if hasattr(loadedPackages, name):
70+
delattr(loadedPackages, name)
71+
else:
72+
# This should not happen, but just in case
73+
warnings.warn(
74+
f"WARNING: a package '{name}' was not found in loadedPackages.",
75+
stacklevel=1,
76+
)
77+
78+
importlib.invalidate_caches()

0 commit comments

Comments
 (0)