Skip to content

Conversation

@marcoesters
Copy link
Contributor

@marcoesters marcoesters commented Oct 16, 2025

Description

Remove custom Python commands for conda-standalone versions that support the windows subcommand (see conda/conda-standalone#197).

This also paves the way for removing python as a required dependency, so I only added it where it may still be needed. The tricky example I haven't tackled yet is mamba v1 vs. v2.

Note that I am using a fairly blunt instrument for the Python-specific parts of the EXE installer. A more fine-tuned way should be implemented with #1003 and #1004.

Closes #549

Checklist - did you ...

  • Add a file to the news directory (using the template) for the next release's release notes?
  • Add / update necessary tests?
  • Add / update outdated documentation?

@conda-bot conda-bot added the cla-signed [bot] added once the contributor has signed the CLA label Oct 16, 2025
@github-project-automation github-project-automation bot moved this to 🆕 New in 🔎 Review Oct 16, 2025
@marcoesters marcoesters marked this pull request as ready for review October 20, 2025 21:27
@marcoesters marcoesters requested a review from a team as a code owner October 20, 2025 21:27
capture_output=True,
check=False,
)
if results.returncode == 2:
Copy link
Contributor

Choose a reason for hiding this comment

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

For clarity, could we add a comment here explaining what returncode 2 means?

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed


if variables["has_python"]:
variables["register_python"] = info.get("register_python", True)
variables["register_python_default"] = info.get("register_python_default", None)
Copy link
Contributor

@lrandersson lrandersson Oct 21, 2025

Choose a reason for hiding this comment

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

I'm just curious, why is register_python_default typed as bool | None but by default False? Does None lead to any different behavior compared to False? To my understanding it seems like it could be a strict boolean and get rid of None.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way these flags are handled needs to be changed. See the issues I linked in the PR description. This is out of scope for this PR though.

if results.returncode == 2:
return True
specs = {MatchSpec(spec) for spec in info.get("specs", ())}
# mamba 2 and newer does not need Python. However, without running the solver,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should assume we'd get mamba 2.x here. We can add an additional post-solve check to make sure we didn't use mamba 1.x.

Comment on lines +327 to +330
{%- else %}
Install for just me and add to PATH:$\n\
> $EXEFILE /AddToPath=1$\n\
{%- endif %}
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this option depend on having Python or not? I'd say the are independent:

Suggested change
{%- else %}
Install for just me and add to PATH:$\n\
> $EXEFILE /AddToPath=1$\n\
{%- endif %}
{%- endif %}
Install for just me and add to PATH:$\n\
> $EXEFILE /AddToPath=1$\n\

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't depend on Python, no, but I figured I'd not add an extra line to the output since it already has to be broken apart.

Copy link
Contributor

Choose a reason for hiding this comment

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

it already has to be broken apart.

I don't get this part. Are they mutually exclusive or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They are not mutually exclusive, I just didn't want the message to be overly long with examples. I was referring to the comment a few lines above:

        # There seems to be a limit to how many chars per ${Print} we can pass.
        # The message will get truncated silently, no errors.
        # That's why we split the help message in two calls.

Copy link
Contributor

Choose a reason for hiding this comment

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

In that case we can split the help message in one more call. I'd rather leave the examples there.

variables["register_python_default"] = info.get("register_python_default", None)
default_uninstall_name += " (Python ${PYVERSION} ${ARCH})"
else:
variables["register_python"] = False
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also define register_python_default here for completeness?

push 'WithLog'
call ${un}AbortRetryNSExecWait
{%- else %}
StrCpy $R0 "Library\mingw-w64\bin Library\usr\bin Library\bin Scripts"
Copy link
Contributor

Choose a reason for hiding this comment

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

I wish we didn't need to hardcode this here. Wouldn't it be more adequate to have this logic in conda-standalone too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It has to be hard-coded somewhere. I made the choice to have an abstract feature in conda-standalone and let the installer implementation decide which paths to add. Do you think it's better to have conda-standalone do the special-casing?

Copy link
Contributor

@jaimergp jaimergp Oct 24, 2025

Choose a reason for hiding this comment

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

My concern is that these directories are defined by convention (although we're trying to standardize it here when building packages, so if at some point we decide to put binaries somewhere else in Windows (e.g. removing the Library/ bit), this hardcoded list might be too far removed from lists defined in other places like conda or other CLIs.

A future addition might be an arm64 implementation of mingw, which would need to be added here.

That said, we can address that in a future refactor. For now let's link to the CEP draft.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm a little concerned to leave this to a future refactor. If this gets moved into conda-standalone, we have to do yet another version check and adjust the template. I think I would rather implement this in conda-standalone then, which is probably much better at architecture detection than NSIS.

Comment on lines +1499 to +1509
{%- if base_needs_python %}
{%- if initialize_conda == 'condabin' %}
${Print} "Adding $INSTDIR\condabin to PATH..."
push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addcondabinpath'
${Print} "Adding $INSTDIR\condabin to PATH..."
push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addcondabinpath'
{%- else %}
${Print} "Adding $INSTDIR\Scripts & Library\bin to PATH..."
push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addpath ${PYVERSION} ${NAME} ${VERSION} ${ARCH}'
${Print} "Adding $INSTDIR\Scripts & Library\bin to PATH..."
push '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addpath ${PYVERSION} ${NAME} ${VERSION} ${ARCH}'
{%- endif %}
push 'Failed to add {{ NAME }} to PATH'
push 'WithLog'
call AbortRetryNSExecWait
push 'Failed to add {{ NAME }} to PATH'
push 'WithLog'
call AbortRetryNSExecWait
Copy link
Contributor

@jaimergp jaimergp Oct 23, 2025

Choose a reason for hiding this comment

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

Why do we implement this twice? Can't we just depend on the new NSIS macro?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you suggesting that I move the if base_needs_python logic into the macro instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

From what I can understand, the AddRemovePath macro already implements the same behavior as '"$INSTDIR\pythonw.exe" -E -s "$INSTDIR\Lib\_nsis.py" addcondabinpath | addpath', so I'm wondering whether we need to keep both. If the macro is sufficient, then we don't need the Python-based logic, do we?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The macro implements the same behavior using conda-standalone. However, that requires the conda constructor windows subcommand to be available, which is currently only the case for the canary builds. The python commands must stay available for now to ensure backwards compatibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

However, your comment makes me think that it's better to move that logic into the macro, too. I will go ahead and do that - it should clear this up a little more.

Copy link
Contributor

Choose a reason for hiding this comment

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

Works for me. Let's leave a comment to deprecate that part once we bump the minimum conda requirement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed [bot] added once the contributor has signed the CLA

Projects

Status: 🆕 New

Development

Successfully merging this pull request may close these issues.

RFC: Undoing constructor / conda-standalone cross "bundling"

4 participants