Skip to content

Commit 303966a

Browse files
committed
Correct user-facing Conda terminology
1 parent 6f0ef74 commit 303966a

37 files changed

Lines changed: 327 additions & 301 deletions

README.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,24 @@ supported and will result in an error.
4747
To check if your base environment is protected, run:
4848

4949
```
50-
conda doctor base-protection
50+
conda doctor -n base base-protection
5151
```
5252

5353
To protect your base environment, run:
5454

5555
```
56-
conda doctor base-protection --fix
56+
conda doctor -n base base-protection --fix
5757
```
5858

5959
This will:
60-
1. Clone your current base environment to a new "default" environment
61-
2. Reset base to conda, conda-self, configured permanent packages, their
62-
dependencies, and installed packages named in an available installer
63-
snapshot
64-
3. Mark the base environment as frozen to prevent modifications
60+
61+
1. Try to save a snapshot of base in conda's explicit format
62+
2. Clone your current base environment to a new "default" environment
63+
3. Remove conda packages other than conda, conda-self, configured permanent
64+
packages, their dependencies, and installed conda packages named in an
65+
available installer snapshot
66+
4. Mark the base environment as frozen so conda refuses modifications by
67+
default
6568

6669
To see all available health checks, run:
6770

@@ -75,12 +78,13 @@ To remove protection entirely, delete the `conda-meta/frozen` environment
7578
marker file:
7679

7780
```
78-
rm $CONDA_PREFIX/conda-meta/frozen
81+
rm "$(conda info --base)/conda-meta/frozen"
7982
```
8083

81-
To bypass protection for a single command, pass `--override-frozen` or set
82-
`CONDA_OVERRIDE_FROZEN=1`. To disable it permanently, add `override_frozen: true`
83-
to your `.condarc`.
84+
To bypass protection for a single command, pass `--override-frozen`. To disable
85+
frozen-environment checks through configuration, set
86+
`CONDA_PROTECT_FROZEN_ENVS=false` or add `protect_frozen_envs: false` to your
87+
`.condarc`.
8488

8589
## Configuration
8690

conda_self/cli/main_install.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def configure_parser(parser: argparse.ArgumentParser) -> None:
1616
parser.add_argument(
1717
"--force-reinstall",
1818
action="store_true",
19-
help="Reinstall each requested plugin even if it is already installed.",
19+
help="Reinstall each requested package even if it is already installed.",
2020
)
2121
parser.add_argument("specs", nargs="+", help="Conda plugins to install")
2222
parser.set_defaults(func=execute)
@@ -44,7 +44,7 @@ def execute(args: argparse.Namespace) -> int:
4444
"Configure channels via `conda config --add channels <channel>` instead."
4545
)
4646

47-
print("Installing plugins:", *args.specs)
47+
print("Installing packages:", *args.specs)
4848

4949
returncode = install_specs_in_protected_env(
5050
args.specs,

conda_self/cli/main_remove.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ def configure_parser(parser: argparse.ArgumentParser) -> None:
1818
"--force",
1919
action="store_true",
2020
help=(
21-
"Remove packages protected from removal because they are permanent "
22-
"or dependencies of permanent packages. Permanent packages are "
23-
"hard-coded or configured via `plugins.self_permanent_packages`. "
24-
"Confirmation is still required unless `--yes` is passed."
21+
"Bypass conda-self's check for permanent packages and their "
22+
"dependencies. Conda still applies its own transaction checks. "
23+
"Confirmation is still required unless --yes is passed."
2524
),
2625
)
2726
parser.add_argument("specs", nargs="+", help="Conda plugins to remove")
@@ -44,16 +43,15 @@ def execute(args: argparse.Namespace) -> int:
4443

4544
if protected_specs:
4645
print(
47-
"Warning: the following packages are protected from removal "
48-
"and will be removed because `--force` was passed:",
46+
"Warning: --force bypassed conda-self's check for the following packages:",
4947
", ".join(protected_specs),
5048
file=sys.stderr,
5149
)
5250

53-
print("Removing plugins:", *args.specs)
51+
print("Removing packages:", *args.specs)
5452

5553
confirm_yn(
56-
"Proceed with removing plugins?[y/n]:\n",
54+
"Proceed with removing packages?[y/n]:\n",
5755
default="no",
5856
dry_run=context.dry_run,
5957
)

conda_self/cli/main_reset.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
class Snapshot(Enum):
1616
"""Snapshot modes accepted by ``conda self reset --snapshot``.
1717
18-
Plain :class:`enum.Enum` for Python 3.10 compatibility; the string values
18+
Plain :class:`enum.Enum` for Python 3.10 compatibility. The string values
1919
double as argparse choices and user-facing mode names. Switch to
2020
:class:`enum.StrEnum` when 3.11 becomes the minimum supported version
2121
(mirrors the TODO on conda's ``EnvironmentFormat``).
@@ -46,7 +46,7 @@ def file_path(self) -> Path | None:
4646
return None
4747

4848

49-
# Tried in order when --snapshot is not provided; the first mode whose file
49+
# Tried in order when --snapshot is not provided. The first mode whose file
5050
# exists on disk wins, otherwise we fall through to CURRENT.
5151
FALLBACK_ORDER: tuple[Snapshot, ...] = (
5252
Snapshot.BASE_PROTECTION,
@@ -58,15 +58,16 @@ def file_path(self) -> Path | None:
5858
SNAPSHOT_HELP = dedent(
5959
"""
6060
Reset mode for the base environment.
61-
`current` removes all packages except for `conda`, `conda-self`, installed
62-
conda plugins, configured permanent packages, and their dependencies.
63-
`installer` restores the exact packages recorded by the installer and
64-
may downgrade updated packages. `installer-exact` is equivalent.
61+
`current` removes all conda packages except for `conda`, `conda-self`,
62+
installed conda plugins, configured permanent packages, and their
63+
dependencies.
64+
`installer` restores exactly the conda packages recorded by the installer
65+
and may downgrade updated packages. `installer-exact` is equivalent.
6566
`installer-updated` retains the packages kept by `current` and currently
66-
installed packages whose names appear in the installer snapshot. It does
67-
not update packages or install missing packages.
68-
`base-protection` restores the exact packages recorded by
69-
`conda doctor base-protection --fix` before protecting base.
67+
installed conda packages whose names appear in the installer snapshot. It
68+
does not update packages or install missing packages.
69+
`base-protection` restores exactly the conda packages recorded by
70+
`conda doctor -n base base-protection --fix` before protecting base.
7071
7172
If not set, `conda self` selects `base-protection` when its snapshot file
7273
exists, otherwise `installer-updated` when the installer snapshot file
@@ -78,13 +79,13 @@ def file_path(self) -> Path | None:
7879
"""
7980
This resets the base environment to keep conda, conda-self, installed conda
8081
plugins, configured permanent packages, and their dependencies.
81-
All other packages are removed.
82+
All other conda packages are removed.
8283
"""
8384
).lstrip()
8485
WHAT_TO_EXPECT_SNAPSHOT = dedent(
8586
"""
8687
This resets the base environment using the '{mode_name}' mode
87-
and removes packages not retained by that mode.
88+
and removes conda packages not retained by that mode.
8889
"""
8990
).lstrip()
9091
SUCCESS = "Reset the base environment using the 'current' mode.\n"
@@ -128,7 +129,7 @@ def execute(args: argparse.Namespace) -> int:
128129

129130
if reset_file is not None and not reset_file.exists():
130131
raise FileNotFoundError(
131-
f"Failed to reset to '{snapshot}'.\nRequired file {reset_file} not found."
132+
f"Snapshot file for the '{snapshot}' reset mode not found: {reset_file}"
132133
)
133134

134135
if not context.json and not context.quiet:

conda_self/exceptions.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@ class NotAPluginError(CondaError):
1616
def __init__(self, specs: list[str]):
1717
names = ", ".join(specs)
1818
if len(specs) == 1:
19-
msg = f"The requested package is not a plugin: {names}"
19+
msg = f"The requested package is not a conda plugin: {names}"
2020
else:
21-
msg = f"The requested packages are not plugins: {names}"
21+
msg = f"The requested packages are not conda plugins: {names}"
2222
super().__init__(msg)
2323

2424

2525
class PluginRemoveError(CondaError):
2626
def __init__(self, specs: list[str]):
2727
names = ", ".join(specs)
2828
noun = _plural("package", len(specs))
29-
super().__init__(f"{noun.capitalize()} cannot be removed: {names}")
29+
super().__init__(
30+
f"conda-self protects the requested {noun} from removal: {names}\n"
31+
"Pass --force to bypass this check. Conda's own transaction checks "
32+
"still apply."
33+
)
3034

3135

3236
class NoDistInfoDirFound(CondaError):

conda_self/health_checks/base_protection.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,18 @@ def check(prefix: str, _verbose: bool) -> None:
4646
return
4747

4848
if is_base_protected():
49-
print(f"{OK_MARK} Base environment is protected (frozen).\n")
49+
print(f"{OK_MARK} Base environment is marked as frozen.\n")
5050
else:
51-
print(f"{X_MARK} Base environment is not protected.\n")
52-
print("Run 'conda doctor base-protection --fix' to protect it.\n")
51+
print(f"{X_MARK} Base environment is not marked as frozen.\n")
52+
print("Run 'conda doctor -n base base-protection --fix' to protect it.\n")
5353

5454

5555
def fix(prefix: str, args: Namespace, confirm: ConfirmCallback) -> int:
5656
"""Fix: Protect the base environment.
5757
5858
This clones the base environment to a new 'default' environment,
59-
removes packages not retained by base protection, and marks it as frozen.
59+
removes conda packages not retained by base protection, and marks it as
60+
frozen.
6061
"""
6162
from pathlib import Path
6263

@@ -101,15 +102,21 @@ def fix(prefix: str, args: Namespace, confirm: ConfirmCallback) -> int:
101102
"and mark it as frozen."
102103
)
103104
if env.external_packages:
105+
external_package_count = len(env.external_packages)
106+
external_package_noun = (
107+
"package" if external_package_count == 1 else "packages"
108+
)
104109
print(
105-
f" Warning: Base environment contains {len(env.external_packages)} "
106-
"non-conda package(s) that will become non-functional after reset.\n"
110+
f" Warning: Base environment contains {external_package_count} "
111+
f"external {external_package_noun} that may no longer work in "
112+
"the reset base environment.\n"
107113
f" They are preserved in the cloned '{default_env}' environment."
108114
)
109115
confirm("Proceed?")
110116

111117
# Prefer the installer snapshot for resetting base so that
112-
# installer-provided packages (e.g. mamba in Miniforge) are preserved.
118+
# packages recorded in the installer snapshot (e.g. mamba in Miniforge)
119+
# are preserved.
113120
installer_snapshot = base_prefix / "conda-meta" / RESET_FILE_INSTALLER
114121
use_snapshot = installer_snapshot.exists()
115122

@@ -133,7 +140,10 @@ def fix(prefix: str, args: Namespace, confirm: ConfirmCallback) -> int:
133140
snapshot_file.write_text(explicit_exporter.export(env))
134141
except CondaValueError:
135142
if not context.quiet:
136-
print(" Skipping snapshot (non-conda packages present).")
143+
print(
144+
" Skipping snapshot because the base environment cannot be "
145+
"exported in conda's explicit format."
146+
)
137147

138148
if not context.quiet:
139149
print(f"Cloning the base environment to '{default_env}'...")
@@ -159,7 +169,7 @@ def fix(prefix: str, args: Namespace, confirm: ConfirmCallback) -> int:
159169
frozen_path = base_prefix / PREFIX_FROZEN_FILE
160170
frozen_path.write_text(json.dumps({"message": message}) if message else "")
161171
except OSError as e:
162-
raise CondaOSError(f"Could not protect environment: {e}") from e
172+
raise CondaOSError(f"Could not protect the base environment: {e}") from e
163173

164174
# Update default activation environment
165175
if not context.quiet:

conda_self/reset.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,14 @@ def records_from_snapshot(
9494
spec.get_exact_value("fn") or spec.name for spec in unresolved_specs
9595
)
9696
raise CondaError(
97-
"Could not download or extract all packages required by the "
98-
"selected snapshot.\n"
99-
"Required packages:%(packages)s\n"
100-
"The target environment was not changed. Some downloaded or "
101-
"extracted packages may remain in a package cache. Ensure each "
102-
"listed package is available from a package cache or can be "
103-
"downloaded from its URL in the snapshot, verified against its "
104-
"recorded checksum when present, and extracted, then retry.",
97+
"Could not make all conda packages required by the selected "
98+
"snapshot available in a package cache.\n"
99+
"Required conda packages:%(packages)s\n"
100+
"The target environment was not changed. Some conda packages "
101+
"may have been downloaded and extracted into a package cache. "
102+
"Ensure each listed package is available in a package cache or "
103+
"can be downloaded from the URL in the snapshot, verified using "
104+
"its recorded checksum when present, and extracted, then retry.",
105105
packages=packages,
106106
) from None
107107

@@ -146,7 +146,8 @@ def reset(
146146
if not context.json and not context.quiet:
147147
print(
148148
"Nothing to do. "
149-
"Packages in the target environment match the selected snapshot."
149+
"The conda packages in the target environment match the "
150+
"selected snapshot."
150151
)
151152
return
152153
else:

demos/base-protection.gif

11.1 KB
Loading

demos/base-protection.mp4

-129 KB
Binary file not shown.

demos/base-protection.tape

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Type "# Check if your base environment is protected"
1616
Enter
1717
Sleep 500ms
1818

19-
Type@80ms "conda doctor base-protection"
19+
Type@80ms "conda doctor -n base base-protection"
2020
Enter
2121
Wait /\$/
2222
Sleep 3s
@@ -25,7 +25,7 @@ Type "# Enable protection: clone base, reset, mark as frozen"
2525
Enter
2626
Sleep 500ms
2727

28-
Type@80ms "conda doctor base-protection --fix --yes"
28+
Type@80ms "conda doctor -n base base-protection --fix --yes"
2929
Enter
3030
Wait /\$/
3131
Sleep 3s
@@ -34,7 +34,7 @@ Type "# Verify protection status"
3434
Enter
3535
Sleep 500ms
3636

37-
Type@80ms "conda doctor base-protection"
37+
Type@80ms "conda doctor -n base base-protection"
3838
Enter
3939
Wait /\$/
4040
Sleep 3s

0 commit comments

Comments
 (0)