Skip to content

Commit

Permalink
Some refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanking13 committed Apr 25, 2023
1 parent 85e2415 commit 89a7f0d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 61 deletions.
11 changes: 9 additions & 2 deletions micropip/_commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from packaging.markers import default_environment

from .._compat import loadPackage, to_js
from .._uninstall import _uninstall
from ..constants import FAQ_URLS
from ..transaction import Transaction
from .uninstall import uninstall


async def install(
Expand Down Expand Up @@ -128,7 +128,14 @@ async def install(
[pkg.name for pkg in transaction.pyodide_packages]
)

uninstall(packages_all, ignore_missing=True)
distributions = []
for pkg_name in packages_all:
try:
distributions.append(importlib.metadata.distribution(pkg_name))
except importlib.metadata.PackageNotFoundError:
pass

_uninstall(distributions)

wheel_promises = []
# Install built-in packages
Expand Down
64 changes: 5 additions & 59 deletions micropip/_commands/uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
from collections.abc import Iterable
from importlib.metadata import Distribution

from .._compat import loadedPackages
from .._utils import get_files_in_distribution, get_root
from .._uninstall import _uninstall


def uninstall(packages: str | Iterable[str], *, ignore_missing: bool = False) -> None:
def uninstall(packages: str | Iterable[str]) -> None:
"""Uninstall the given packages.
This function only supports uninstalling packages that are installed
Expand All @@ -23,9 +22,6 @@ def uninstall(packages: str | Iterable[str], *, ignore_missing: bool = False) ->
----------
packages
Packages to uninstall.
_ignore_missing
If ``True``, suppress warnings when a package is not installed.
"""

if isinstance(packages, str):
Expand All @@ -37,61 +33,11 @@ def uninstall(packages: str | Iterable[str], *, ignore_missing: bool = False) ->
dist = importlib.metadata.distribution(package)
distributions.append(dist)
except importlib.metadata.PackageNotFoundError:
if not ignore_missing: # TODO: Can we utilize log level here?
warnings.warn(
f"WARNING: Skipping '{package}' as it is not installed.",
stacklevel=1,
)

for dist in distributions:
# Note: this value needs to be retrieved before removing files, as
# dist.name uses metadata file to get the name
name = dist.name

root = get_root(dist)
files = get_files_in_distribution(dist)
directories = set()

for file in files:
if not file.is_file():
if not file.is_relative_to(root):
# This file is not in the site-packages directory. Probably one of:
# - data_files
# - scripts
# - entry_points
# Since we don't support these, we can ignore them (except for data_files (TODO))
continue

warnings.warn(
f"WARNING: A file '{file}' listed in the metadata of '{dist.name}' does not exist.",
stacklevel=1,
)

continue

file.unlink()

if file.parent != root:
directories.add(file.parent)

# Remove directories in reverse hierarchical order
for directory in sorted(directories, key=lambda x: len(x.parts), reverse=True):
try:
directory.rmdir()
except OSError:
warnings.warn(
f"WARNING: A directory '{directory}' is not empty after uninstallation of '{name}'. "
"This might cause problems when installing a new version of the package. ",
stacklevel=1,
)

if hasattr(loadedPackages, name):
delattr(loadedPackages, name)
else:
# This should not happen, but just in case
warnings.warn(
f"WARNING: a package '{name}' was not found in loadedPackages.",
f"WARNING: Skipping '{package}' as it is not installed.",
stacklevel=1,
)

_uninstall(distributions)

importlib.invalidate_caches()
78 changes: 78 additions & 0 deletions micropip/_uninstall.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import importlib
import importlib.metadata
import warnings
from collections.abc import Iterable
from importlib.metadata import Distribution

from .._compat import loadedPackages
from .._utils import get_files_in_distribution, get_root


def _uninstall(distributions: Iterable[Distribution]) -> None:
"""Uninstall the given package distributions.
This function does not do any checks, so make sure that the distributions
are installed and that they are installed using a wheel file, i.e. packages
that have distribution metadata.
This function also does not invalidate the import cache, so make sure to
call `importlib.invalidate_caches()` after calling this function.
Parameters
----------
distributions
Package distributions to uninstall.
"""

for dist in distributions:
# Note: this value needs to be retrieved before removing files, as
# dist.name uses metadata file to get the name
name = dist.name

root = get_root(dist)
files = get_files_in_distribution(dist)
directories = set()

for file in files:
if not file.is_file():
if not file.is_relative_to(root):
# This file is not in the site-packages directory. Probably one of:
# - data_files
# - scripts
# - entry_points
# Since we don't support these, we can ignore them (except for data_files (TODO))
continue

warnings.warn(
f"WARNING: A file '{file}' listed in the metadata of '{dist.name}' does not exist.",
stacklevel=1,
)

continue

file.unlink()

if file.parent != root:
directories.add(file.parent)

# Remove directories in reverse hierarchical order
for directory in sorted(directories, key=lambda x: len(x.parts), reverse=True):
try:
directory.rmdir()
except OSError:
warnings.warn(
f"WARNING: A directory '{directory}' is not empty after uninstallation of '{name}'. "
"This might cause problems when installing a new version of the package. ",
stacklevel=1,
)

if hasattr(loadedPackages, name):
delattr(loadedPackages, name)
else:
# This should not happen, but just in case
warnings.warn(
f"WARNING: a package '{name}' was not found in loadedPackages.",
stacklevel=1,
)

importlib.invalidate_caches()

0 comments on commit 89a7f0d

Please sign in to comment.