Skip to content

Commit 78e4b84

Browse files
soapy1jaimergp
andauthored
Remove package from base environment (#5)
Co-authored-by: jaimergp <jaimergp@users.noreply.github.com>
1 parent d13d7c9 commit 78e4b84

6 files changed

Lines changed: 69 additions & 3 deletions

File tree

conda_self/cli/main_remove.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,25 @@
1010

1111
def configure_parser(parser: argparse.ArgumentParser) -> None:
1212
parser.description = HELP
13-
parser.add_argument("specs", nargs="+", help="Plugins to install")
13+
parser.add_argument("specs", nargs="+", help="Plugins to remove/uninstall")
1414
parser.set_defaults(func=execute)
1515

1616

1717
def execute(args: argparse.Namespace) -> int:
18+
from ..exceptions import SpecsCanNotBeRemoved
19+
from ..query import permanent_dependencies
20+
from ..install import uninstall_specs_in_protected_env
21+
22+
uninstallable_packages = permanent_dependencies()
23+
invalid_specs = []
24+
for spec in args.specs:
25+
if spec in uninstallable_packages:
26+
invalid_specs.append(spec)
27+
28+
if invalid_specs:
29+
raise SpecsCanNotBeRemoved(invalid_specs)
30+
1831
print("Removing plugins:", *args.specs)
32+
33+
uninstall_specs_in_protected_env(args.specs, yes=False)
1934
return 0

conda_self/cli/main_update.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def execute(args: argparse.Namespace) -> int:
3737
from conda.reporters import get_spinner
3838

3939
from ..query import check_updates
40-
from ..update import install_package_in_protected_env
40+
from ..install import install_package_in_protected_env
4141
from ..validate import validate_plugin_is_installed
4242

4343
if args.plugin:

conda_self/constants.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from typing import Final
2+
3+
PERMANENT_PACKAGES: Final = (
4+
"conda",
5+
)

conda_self/exceptions.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@
33

44
class SpecsAreNotPlugins(CondaError):
55
def __init__(self, specs: list[str]):
6-
super().__init__(f"The following requested specs are not plugins: {specs}")
6+
super().__init__(f"The following requested specs are not plugins: {specs}")
7+
8+
9+
class SpecsCanNotBeRemoved(CondaError):
10+
def __init__(self, specs: list[str]):
11+
super().__init__(f"Packages '{specs}' can not be removed.")
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,27 @@ def install_package_in_protected_env(
3232
]
3333
)
3434
return process.returncode
35+
36+
37+
def uninstall_specs_in_protected_env(
38+
specs: list[str],
39+
json: bool = False,
40+
yes: bool = True,
41+
) -> int:
42+
cmd = [
43+
sys.executable,
44+
"-m",
45+
"conda",
46+
"remove",
47+
f"--prefix={sys.prefix}",
48+
*(
49+
("--override-frozen",)
50+
if hasattr(context, "protect_frozen_envs")
51+
else ()
52+
),
53+
*(("--json",) if json else ()),
54+
*(("--yes",) if yes else ()),
55+
*specs
56+
]
57+
process = run(cmd)
58+
return process.returncode

conda_self/query.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import sys
6+
from functools import cache
67
from typing import TYPE_CHECKING
78

89
from conda.base.context import context
@@ -13,8 +14,11 @@
1314
PackagesNotFoundError,
1415
)
1516
from conda.models.channel import Channel
17+
from conda.models.prefix_graph import PrefixGraph
1618
from conda.models.version import VersionOrder
1719

20+
from .constants import PERMANENT_PACKAGES
21+
1822
if TYPE_CHECKING:
1923
from collections.abc import Iterable
2024

@@ -56,3 +60,16 @@ def latest(
5660
if best is None:
5761
raise PackagesNotFoundError(package_name, channels)
5862
return best
63+
64+
65+
@cache
66+
def permanent_dependencies() -> set[str]:
67+
"""Get the full list of dependencies for all the permanent packages."""
68+
installed = PrefixData(sys.prefix)
69+
prefix_graph = PrefixGraph(installed.iter_records())
70+
71+
packages = []
72+
for pkg in PERMANENT_PACKAGES:
73+
node = prefix_graph.get_node_by_name(pkg)
74+
packages.extend([record.name for record in prefix_graph.all_ancestors(node)])
75+
return set(packages)

0 commit comments

Comments
 (0)