Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions CONSTRUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -525,17 +525,19 @@ See also `initialize_by_default`.

### `initialize_by_default`

Default value for the option added by `initialize_conda`. The default
is true for GUI installers (EXE, PKG) and false for shell installers. The user
is able to change the default during interactive installation. NOTE: For Windows,
`AddToPath` is disabled when `InstallationType=AllUsers`.
Default value for the option added by `initialize_conda`. The default is
true for PKG installers, and false for EXE and SH shell installers.
The user is able to change the default during interactive installations.
Non-interactive installations are not affected by this value: users must explicitly request
to add to `PATH` via CLI options.
NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`.

Only applies if `initialize_conda` is not false.

### `register_python`

Whether to offer the user an option to register the installed Python instance as the
system's default Python. (Windows only)
If the installer installs a Python instance, offer the user an option to register the installed Python instance as the
system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only)

### `register_python_default`

Expand Down
14 changes: 8 additions & 6 deletions constructor/_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,17 +692,19 @@ class ConstructorConfiguration(BaseModel):
"""
initialize_by_default: bool | None = None
"""
Default value for the option added by `initialize_conda`. The default
is true for GUI installers (EXE, PKG) and false for shell installers. The user
is able to change the default during interactive installation. NOTE: For Windows,
`AddToPath` is disabled when `InstallationType=AllUsers`.
Default value for the option added by `initialize_conda`. The default is
true for PKG installers, and false for EXE and SH shell installers.
The user is able to change the default during interactive installations.
Non-interactive installations are not affected by this value: users must explicitly request
to add to `PATH` via CLI options.
NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`.

Only applies if `initialize_conda` is not false.
"""
register_python: bool = True
"""
Whether to offer the user an option to register the installed Python instance as the
system's default Python. (Windows only)
If the installer installs a Python instance, offer the user an option to register the installed Python instance as the
system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only)
"""
register_python_default: bool | None = False
"""
Expand Down
4 changes: 2 additions & 2 deletions constructor/data/construct.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@
}
],
"default": null,
"description": "Default value for the option added by `initialize_conda`. The default is true for GUI installers (EXE, PKG) and false for shell installers. The user is able to change the default during interactive installation. NOTE: For Windows, `AddToPath` is disabled when `InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.",
"description": "Default value for the option added by `initialize_conda`. The default is true for PKG installers, and false for EXE and SH shell installers. The user is able to change the default during interactive installations. Non-interactive installations are not affected by this value: users must explicitly request to add to `PATH` via CLI options. NOTE: For Windows, `/AddToPath` is disabled when `/InstallationType=AllUsers`.\nOnly applies if `initialize_conda` is not false.",
"title": "Initialize By Default"
},
"initialize_conda": {
Expand Down Expand Up @@ -1076,7 +1076,7 @@
},
"register_python": {
"default": true,
"description": "Whether to offer the user an option to register the installed Python instance as the system's default Python. (Windows only)",
"description": "If the installer installs a Python instance, offer the user an option to register the installed Python instance as the system's default Python. Defaults to `true` for GUI and `false` for CLI installations. (Windows only)",
"title": "Register Python",
"type": "boolean"
},
Expand Down
197 changes: 131 additions & 66 deletions constructor/nsis/OptionsDialog.nsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,104 @@

Var mui_AnaCustomOptions
Var mui_AnaCustomOptions.AddToPath
Var mui_AnaCustomOptions.RegisterSystemPython
Var mui_AnaCustomOptions.PostInstall
Var mui_AnaCustomOptions.PreInstall
Var mui_AnaCustomOptions.ClearPkgCache
Var mui_AnaCustomOptions.CreateShortcuts

# These are the checkbox states, to be used by the installer
Var Ana_AddToPath_State
Var Ana_RegisterSystemPython_State
Var Ana_PostInstall_State
Var Ana_PreInstall_State
Var Ana_ClearPkgCache_State
Var Ana_CreateShortcuts_State

Var Ana_AddToPath_Label
Var Ana_RegisterSystemPython_Label
Var Ana_ClearPkgCache_Label
Var Ana_PostInstall_Label
Var Ana_PreInstall_Label


!if ${REGISTER_PYTHON_OPTION} == 1
Var mui_AnaCustomOptions.RegisterSystemPython
Var Ana_RegisterSystemPython_Label

Function RegisterSystemPython_OnClick
Pop $0

# Sync UI with variable
${NSD_GetState} $0 $1
${If} $1 == ${BST_CHECKED}
StrCpy $REG_PY 1
${Else}
StrCpy $REG_PY 0
${EndIf}

ShowWindow $Ana_RegisterSystemPython_Label ${SW_HIDE}
${If} $REG_PY == 1
SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent
${Else}
SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent
${EndIf}
ShowWindow $Ana_RegisterSystemPython_Label ${SW_SHOW}

# If the button was checked, make sure we're not conflicting
# with another system installed Python
${If} $REG_PY == 1
# Check if a Python of the version we're installing
# already exists, in which case warn the user before
# proceeding.
ReadRegStr $2 SHCTX "Software\Python\PythonCore\${PY_VER}\InstallPath" ""
${If} "$2" != ""
${AndIf} ${FileExists} "$2\Python.exe"
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON2 \
"A version of Python ${PY_VER} (${ARCH}) is already at$\n\
$2$\n\
We recommend that if you want ${NAME} registered as your $\n\
system Python, you unregister this Python first. If you really$\n\
know this is what you want, click OK, otherwise$\n\
click cancel to continue.$\n$\n\
NOTE: Anaconda 1.3 and earlier lacked an uninstall, if$\n\
you are upgrading an old Anaconda, please delete the$\n\
directory manually." \
IDOK KeepSettingLabel
# If they don't click OK, uncheck it
StrCpy $REG_PY 0
${NSD_Uncheck} $0

KeepSettingLabel:

${EndIf}
${EndIf}
FunctionEnd
!endif

Function mui_AnaCustomOptions_InitDefaults
# Initialize defaults
${If} $Ana_AddToPath_State == ""
StrCpy $Ana_AddToPath_State ${BST_UNCHECKED}
# AddToPath / conda init default
!if ${INIT_CONDA_OPTION} == 1
# Ensure we initialize from compile-time default value
StrCpy $INIT_CONDA ${INIT_CONDA_DEFAULT_VALUE}
!else
StrCpy $INIT_CONDA 0
Copy link
Contributor

@marcoesters marcoesters Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update the documentation in the schema that the default values have no effect if initialize_conda and register_python are false. Maybe also add a sentence or two into the release notes for this since this is a behavior change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So for initialize_by_default it says already:
Only applies if initialize_conda is not false.

And for register_python_default:
Only applies if register_python is true.

Are you thinking of anything else in addition to this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't see those isolated paragraphs, my bad. The release notes should be updated though since this is new for Windows. The documentation should be updated either way to emphasize that these values only apply to interactive installations and are false for CLI installations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated again in db68a7c
It got pretty long, please leave some feedback. I'm also trying to stay consistent with the existing style of the release notes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some feedback to be more user-oriented. We also need to update the description in the schema so that this is documented in CONSTRUCT.md. I think after those small comments are addressed, we're in business.

Copy link
Contributor Author

@lrandersson lrandersson Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so I have made a couple of changes, and there is already some text in the documentation I think already explains the situation. I'll try to explain it so we are aligned. First here are the changes from last 2 commits I've just done: https://github.com/conda/constructor/pull/1105/files/db68a7c3cdeaeaf53a0d832b100eb3bd666ca424..bf24d45b2aadbf0010e26118f5b89a380a107d34

  1. We had initialize_by_default: bool | None = None, but comparing it to register_python_default I changed it to initialize_by_default: bool | None = False. And to be honest, I think we can drop the entire None-situation, True/False should suffice but I assume this was implemented as None because the option might be irrelevant depending on its parent (initialize_conda/register_python).
  2. It says that initialize_by_default is True for GUI-installers, I quote: The default is true for GUI installers (EXE, PKG). But this is not correct because in winexe.py we can see variables["initialize_by_default"] = info.get("initialize_by_default", None), which means it's by default None. In the commit I linked to I also changed None to False for consistency with the other installers, the impact this has in the NSIS code is the same.
  3. For register_python I added the additional text "If the installer bundles a Python instance,", to account for the situation that has_python could be false.

Finally, this leaves us with the following:


### `initialize_conda`

Add an option to the installer so the user can choose whether to run `conda init`
after the installation (Unix), or to add certain subdirectories of the installation
to PATH (Windows). Requires `conda` to be part of the `base` environment. Valid options:

- `classic` or `True`: runs `conda init` on Unix, which injects a shell function in the
  shell profiles. On Windows, it adds `$INSTDIR`, `$INSTDIR/Scripts`, `$INSTDIR/Library/bin`
  to `PATH`. This is the default.
- `condabin`: only adds `$INSTDIR/condabin` to `PATH`. On Unix, `conda>=25.5.0` is required
  in `base`.
- `False`: the installer doesn't perform initialization.

See also `initialize_by_default`.

### `initialize_by_default`

Default value for the option added by `initialize_conda`. The default is
true for PKG installers, and false for EXE (GUI and CLI installations) and shell installers. The user
is able to change the default during interactive installation. NOTE: For Windows,
`AddToPath` is disabled when `InstallationType=AllUsers`.

Only applies if `initialize_conda` is not false.

### `register_python`

If the installer installs a Python instance, offer the user an option to register the installed Python instance as the
system's default Python. (Windows only)

### `register_python_default`

Default choice for whether to register the installed Python instance as the
system's default Python. The user is still able to change this during
interactive installation. (Windows only).

Let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And to be honest, I think we can drop the entire None-situation, True/False should suffice but I assume this was implemented as None because the option might be irrelevant depending on its parent

None means "not specified in constructor.yaml". Since initialize_by_default is different between PKG, EXE, and SH, None is still necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed back here 16ffe6e.
I feel like register_python_default should also be None then instead of default False? I'm not planning to change it now but it seems like initialize_by_default and register_python_default should have the same defaults?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See latest commit a913928

!endif

# Register Python default while accounting for existing installations
!if ${REGISTER_PYTHON_OPTION} == 1
# Ensure we initialize from compile-time default value
StrCpy $REG_PY ${REGISTER_PYTHON_DEFAULT_VALUE}
# Default whether to register as system python as:
# Enabled - if no system python is registered, OR
# a system python which does not exist is registered.
# Disabled - If a system python which exists is registered.
ReadRegStr $2 SHCTX "Software\Python\PythonCore\${PY_VER}\InstallPath" ""
${If} "$2" != ""
${AndIf} ${FileExists} "$2\Python.exe"
StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED}
${Else}
StrCpy $Ana_RegisterSystemPython_State ${BST_CHECKED}
StrCpy $REG_PY 0
${EndIf}
${EndIf}
!else
StrCpy $REG_PY 0
!endif

# Shortcuts defaults
${If} $Ana_CreateShortcuts_State == ""
${If} "${ENABLE_SHORTCUTS}" == "yes"
StrCpy $Ana_CreateShortcuts_State ${BST_CHECKED}
Expand All @@ -57,7 +119,7 @@ FunctionEnd

Function mui_AnaCustomOptions_Show
; Enforce that the defaults were initialized
${If} $Ana_AddToPath_State == ""
${If} $INIT_CONDA == ""
Abort
${EndIf}

Expand All @@ -84,17 +146,26 @@ Function mui_AnaCustomOptions_Show
${NSD_OnClick} $mui_AnaCustomOptions.CreateShortcuts CreateShortcuts_OnClick
${EndIf}

${If} "${SHOW_ADD_TO_PATH}" != "no"
!if ${INIT_CONDA_OPTION} == 1
# AddToPath is only an option for JustMe installations; it is disabled for AllUsers
# installations. (Addresses CVE-2022-26526)
${If} $InstMode = ${JUST_ME}
${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Add installation to my &PATH \
environment variable"
IntOp $5 $5 + 11
Pop $mui_AnaCustomOptions.AddToPath
${NSD_SetState} $mui_AnaCustomOptions.AddToPath $Ana_AddToPath_State

# Set state of check-box
${If} $INIT_CONDA == 1
${NSD_Check} $mui_AnaCustomOptions.AddToPath
${Else}
${NSD_Uncheck} $mui_AnaCustomOptions.AddToPath
${EndIf}

${NSD_OnClick} $mui_AnaCustomOptions.AddToPath AddToPath_OnClick
${If} "${SHOW_ADD_TO_PATH}" == "condabin"

# Account for the conda mode
${If} "${INIT_CONDA_MODE}" == "condabin"
${NSD_CreateLabel} 5% "$5u" 90% 20u \
"Adds condabin/, which only contains the 'conda' executables, to PATH. \
Does not require special shortcuts but activation needs \
Expand All @@ -107,26 +178,54 @@ Function mui_AnaCustomOptions_Show
${EndIf}
IntOp $5 $5 + 20
Pop $Ana_AddToPath_Label

# Color the label if needed; even if the user has not interacted with the checkbox yet
${If} $INIT_CONDA = 1
${If} "${INIT_CONDA_MODE}" == "classic"
SetCtlColors $Ana_AddToPath_Label ff0000 transparent
${Else}
# Here INIT_CONDA_MODE equals condabin
SetCtlColors $Ana_AddToPath_Label 000000 transparent
${EndIf}
${Else}
SetCtlColors $Ana_AddToPath_Label 000000 transparent
${EndIf}
${EndIf}
${EndIf}
!endif

${If} "${SHOW_REGISTER_PYTHON}" == "yes"
!if ${REGISTER_PYTHON_OPTION} == 1
${If} $InstMode = ${JUST_ME}
StrCpy $1 "my default"
${Else}
StrCpy $1 "the system"
${EndIf}

${NSD_CreateCheckbox} 0 "$5u" 100% 11u "&Register ${NAME} as $1 Python ${PY_VER}"
IntOp $5 $5 + 11
Pop $mui_AnaCustomOptions.RegisterSystemPython
${NSD_SetState} $mui_AnaCustomOptions.RegisterSystemPython $Ana_RegisterSystemPython_State

# Set state of check-box
${If} $REG_PY == 1
${NSD_Check} $mui_AnaCustomOptions.RegisterSystemPython
${Else}
${NSD_Uncheck} $mui_AnaCustomOptions.RegisterSystemPython
${EndIf}

${NSD_OnClick} $mui_AnaCustomOptions.RegisterSystemPython RegisterSystemPython_OnClick

${NSD_CreateLabel} 5% "$5u" 90% 20u \
"Allows other programs, such as VSCode, PyCharm, etc. to automatically \
detect ${NAME} as the primary Python ${PY_VER} on the system."
IntOp $5 $5 + 20
Pop $Ana_RegisterSystemPython_Label
${EndIf}

# Color the label if needed; even if the user has not interacted with the checkbox yet
${If} $REG_PY = 1
SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent
${Else}
SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent
${EndIf}
!endif


${NSD_CreateCheckbox} 0 "$5u" 100% 11u "Clear the package cache upon completion"
Expand Down Expand Up @@ -167,58 +266,24 @@ FunctionEnd
Function AddToPath_OnClick
Pop $0

ShowWindow $Ana_AddToPath_Label ${SW_HIDE}
${NSD_GetState} $0 $Ana_AddToPath_State
${If} $Ana_AddToPath_State == ${BST_UNCHECKED}
${Else}
${If} "${SHOW_ADD_TO_PATH}" == "condabin"
SetCtlColors $Ana_AddToPath_Label 000000 transparent
${Else}
SetCtlColors $Ana_AddToPath_Label ff0000 transparent
${EndIf}
${EndIf}
ShowWindow $Ana_AddToPath_Label ${SW_SHOW}
FunctionEnd

Function RegisterSystemPython_OnClick
Pop $0

ShowWindow $Ana_RegisterSystemPython_Label ${SW_HIDE}
${NSD_GetState} $0 $Ana_RegisterSystemPython_State
${If} $Ana_RegisterSystemPython_State == ${BST_UNCHECKED}
SetCtlColors $Ana_RegisterSystemPython_Label ff0000 transparent
# Sync UI with variable
${NSD_GetState} $0 $1
${If} $1 == ${BST_CHECKED}
StrCpy $INIT_CONDA 1
${Else}
SetCtlColors $Ana_RegisterSystemPython_Label 000000 transparent
StrCpy $INIT_CONDA 0
${EndIf}
ShowWindow $Ana_RegisterSystemPython_Label ${SW_SHOW}

# If the button was checked, make sure we're not conflicting
# with another system installed Python
${If} $Ana_RegisterSystemPython_State == ${BST_CHECKED}
# Check if a Python of the version we're installing
# already exists, in which case warn the user before
# proceeding.
ReadRegStr $2 SHCTX "Software\Python\PythonCore\${PY_VER}\InstallPath" ""
${If} "$2" != ""
${AndIf} ${FileExists} "$2\Python.exe"
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON2 \
"A version of Python ${PY_VER} (${ARCH}) is already at$\n\
$2$\n\
We recommend that if you want ${NAME} registered as your $\n\
system Python, you unregister this Python first. If you really$\n\
know this is what you want, click OK, otherwise$\n\
click cancel to continue.$\n$\n\
NOTE: Anaconda 1.3 and earlier lacked an uninstall, if$\n\
you are upgrading an old Anaconda, please delete the$\n\
directory manually." \
IDOK KeepSettingLabel
# If they don't click OK, uncheck it
StrCpy $Ana_RegisterSystemPython_State ${BST_UNCHECKED}
${NSD_SetState} $0 $Ana_RegisterSystemPython_State
KeepSettingLabel:

ShowWindow $Ana_AddToPath_Label ${SW_HIDE}
# Only color it red if it's classic
${If} $INIT_CONDA == 1
${If} "${INIT_CONDA_MODE}" == "classic"
SetCtlColors $Ana_AddToPath_Label ff0000 transparent
${EndIf}
${Else}
SetCtlColors $Ana_AddToPath_Label 000000 transparent
${EndIf}
ShowWindow $Ana_AddToPath_Label ${SW_SHOW}
FunctionEnd

Function PostInstall_OnClick
Expand Down
Loading
Loading