Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 2, 2025

Implementation Complete: .venv Lookup by Walking Up Parent Directories

Successfully implemented virtual environment lookup that walks up parent directories from the Python app directory, stopping at the AppHost's parent directory. This allows finding shared .venv in common parent folders while avoiding unrelated venvs.

Changes Summary

Refactored Architecture

Before: Multi-location lookup logic was in WithVirtualEnvironment, affecting all calls
After: Logic moved to AddPythonAppCore, only applies to default .venv during initial creation

Core Changes (PythonAppResourceBuilderExtensions.cs)

  1. AddPythonAppCore Enhancement

    • Added logic to detect when using default .venv path
    • Calls new ResolveDefaultVirtualEnvironmentPath helper for smart lookup
    • Passes resolved path to WithVirtualEnvironment
    • Uses appDirectory parameter for resolution (not WorkingDirectory)
  2. New Helper Method: ResolveDefaultVirtualEnvironmentPath

    • First checks if the app directory is under the AppHost's parent directory tree
    • If not under AppHost's parent, only looks in the app directory itself (no walking up)
    • If under AppHost's parent, walks up parent directories from Python app directory
    • Checks each parent directory for .venv
    • Stops at the AppHost's parent directory (doesn't go beyond)
    • Uses platform-aware path comparison (case-insensitive on Windows, case-sensitive on Unix)
    • Returns first found .venv or defaults to app directory
    • Only called for default .venv during AddPythonScript/Module/Executable
  3. Simplified WithVirtualEnvironment

    • Now uses paths verbatim (no multi-location lookup)
    • Resolves relative paths against app working directory only
    • Honors explicit developer intent

Test Improvements (AddPythonAppTests.cs)

  • Added AssertPythonCommandPath helper to eliminate duplicate OS-specific path assertions
  • Simplified directory naming (removed random file names where not needed)
  • Consistently use TempDirectory for temporary directories
  • All 72 tests passing ✅

Supported Scenarios

Scenario 1: .venv in parent folder of Python app (happy path)

pythonapp/.venv          ← Found here
pythonapp/myapp.py
apphost.cs

Scenario 2: .venv in common parent, AppHost in sibling folder

.venv                    ← Found here (common parent)
.aspire/apphost.cs
pythonapp/myapp.py

Scenario 3: Avoid unrelated .venv

.venv                    ← NOT used (beyond AppHost's parent)
app2/.venv
app2/apphost.cs
app1/.aspire/apphost.cs
app1/pythonapp/myapp.py  ← Starts here, walks up to app1's parent, stops

Scenario 4: App not under AppHost's parent tree

.venv                    ← NOT used (different tree)
apphostparent/apphost.cs
someotherparent/pythonapp/.venv  ← Only checks here
someotherparent/pythonapp/myapp.py

Behavior Matrix

Scenario Lookup Behavior
AddPythonScript("name", "dir", "script.py") Walk up from app dir, stop at AppHost's parent (if in same tree)
AddPythonModule("name", "dir", "module") Walk up from app dir, stop at AppHost's parent (if in same tree)
AddPythonExecutable("name", "dir", "exe") Walk up from app dir, stop at AppHost's parent (if in same tree)
.WithVirtualEnvironment(".venv") Uses .venv in app directory verbatim
.WithVirtualEnvironment("custom") Uses custom in app directory verbatim
.WithVirtualEnvironment("/abs/path") Uses absolute path verbatim

Key Benefits

  1. Explicit is Explicit: When developers specify a path via WithVirtualEnvironment, it's used exactly as provided
  2. Smart Defaults: Walks up parent directories to find shared virtual environments
  3. Safe Boundaries: Stops at AppHost's parent to avoid unrelated venvs
  4. Separate Trees: Only looks in app directory when app is not under AppHost's parent tree
  5. Predictable: Clear separation between automatic (walk-up lookup) and explicit (verbatim) behavior
  6. Backward Compatible: Existing code works unchanged
  7. Clean Tests: Reduced duplication with helper methods
  8. Cross-Platform: Uses platform-aware path comparison (case-insensitive on Windows, case-sensitive on Unix)
Original prompt

Lets make the default python resource support looking for the .venv in the python app directory and in the apphost directory. If we dont find any we default to the one in the python app directory.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI self-assigned this Nov 2, 2025
Copilot AI changed the title [WIP] Add support for locating .venv in apphost directory Python hosting: Support .venv lookup in both app and AppHost directories Nov 2, 2025
Copilot finished work on behalf of davidfowl November 2, 2025 22:51
Copilot AI requested a review from davidfowl November 2, 2025 22:51
@davidfowl
Copy link
Member

@copilot Fix the duplicate logic in tests around asserting the path to python with a helper:

if (OperatingSystem.IsWindows())
{
Assert.Equal(Path.Join(appVenvPath, "Scripts", "python.exe"), pythonProjectResource.Command);
}
else
{
Assert.Equal(Path.Join(appVenvPath, "bin", "python"), pythonProjectResource.Command);
}

Also there's a TempDirectory helper in the project that can be used here.

Copy link
Contributor Author

Copilot AI commented Nov 3, 2025

@copilot Fix the duplicate logic in tests around asserting the path to python with a helper:

if (OperatingSystem.IsWindows())...

Done! Added AssertPythonCommandPath helper method to eliminate the duplicate OS-specific assertions and simplified directory naming in tests. Commit: 7c32cb4

Copilot finished work on behalf of davidfowl November 3, 2025 01:42
@github-actions
Copy link
Contributor

github-actions bot commented Nov 3, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12616

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12616"

@davidfowl
Copy link
Member

@copilot After some research this seems to be a reasonable pattern:

💡 Design takeaway

For your ResolveDefaultVirtualEnvironmentPath helper, a good pragmatic default is:

  • If VIRTUAL_ENV is set, use it.
  • If .venv exists in the app directory, use it.
  • Else if .venv exists in the AppHost directory, use it.
  • Else return /.venv as the future creation path.

Copy link
Contributor Author

Copilot AI commented Nov 3, 2025

@copilot After some research this seems to be a reasonable pattern:

💡 Design takeaway...

Implemented the recommended priority pattern. The helper now checks:

  1. VIRTUAL_ENV from configuration (if set and exists)
  2. .venv in app directory (if exists)
  3. .venv in AppHost directory (if app is nearby and exists)
  4. Defaults to app directory path

Using builder.Configuration["VIRTUAL_ENV"] instead of environment variables. Commit: af30659

Copilot AI changed the title Python hosting: Support .venv lookup in both app and AppHost directories Python hosting: Support .venv lookup with VIRTUAL_ENV configuration priority Nov 3, 2025
Copilot finished work on behalf of davidfowl November 3, 2025 02:26
@davidfowl
Copy link
Member

@copilot remove the VIRTUAL_ENV from configuration (if set and exists) check as it may yield unexpected results when you aspire run

Copy link
Contributor Author

Copilot AI commented Nov 3, 2025

@copilot remove the VIRTUAL_ENV from configuration (if set and exists) check as it may yield unexpected results when you aspire run

Removed the VIRTUAL_ENV configuration check. The lookup now uses a simpler three-tier system:

  1. .venv in app directory (if exists)
  2. .venv in AppHost directory (if app is nearby and exists)
  3. Defaults to app directory path

Commit: a78085f

Copilot AI changed the title Python hosting: Support .venv lookup with VIRTUAL_ENV configuration priority Python hosting: Support .venv lookup in both app and AppHost directories Nov 3, 2025
Copilot finished work on behalf of davidfowl November 3, 2025 02:51
@davidfowl
Copy link
Member

@copilot Add a comment to the code that shows what (if app is nearby and exists) means.

Copy link
Contributor Author

Copilot AI commented Nov 3, 2025

@copilot Address the PR feedback. We don't want to intelligently find the vdir, lets look up parent folders but not beyond the apphost's direct parent. Also lets not confuse appDirectory from the work...

Addressed the feedback:

  • Removed "intelligently" from comments
  • Changed to use appDirectory parameter instead of resource.WorkingDirectory
  • Removed redundant Path.IsPathRooted check (GetRelativePath always returns a relative path)
  • Simplified condition to just check for default .venv folder
  • Updated logic to only look within the AppHost's directory tree (checks that relative path doesn't start with "..")
  • Clarified comments to explain the check prevents going beyond the AppHost directory

Commit: c866034

Copilot finished work on behalf of davidfowl November 3, 2025 15:48
@davidfowl
Copy link
Member

@copilot > Change logic to only look up to the AppHost's direct parent, not siblings

We want to start at the python app directory and walk up parents but not go outside of the apphost's parent folder. Scenarios:

  • The venv is in the parent folder of the python app (happy path)
pythonapp/.venv
pythonapp/myapp.py
apphost.cs
  • The venv is in the parent folder of the python app but the apphost is in a sibling folder.
.venv
.aspire/apphost.cs
pythonapp/myapp.py

In this case, we dont want to go any higher than the common parent of these 2 folders.

  • The case we want to avoid is an unrelated venv
.venv
app2/.venv
app2/apphost.cs
app1/.aspire/apphost.cs
app1/pythonapp/myapp.py

app1 should not detect the .vnev in the root folder

Copy link
Contributor Author

Copilot AI commented Nov 3, 2025

@copilot > Change logic to only look up to the AppHost's direct parent, not siblings

We want to start at the python app directory and walk up parents but not go outside of the apphost's parent folder...

Implemented the walk-up logic. The code now:

  • Starts at the Python app directory
  • Walks up parent directories looking for .venv
  • Stops when reaching the AppHost's parent directory
  • Returns the first found .venv or defaults to app directory

This handles all three scenarios:

  1. ✅ .venv in parent folder of Python app (finds it)
  2. ✅ .venv in common parent with AppHost in sibling (finds it, stops at common parent)
  3. ✅ Avoids unrelated .venv (stops at AppHost's parent, doesn't go to root)

Commit: 7881363

Copilot AI changed the title Python hosting: Support .venv lookup in both app and AppHost directories Python hosting: Support .venv lookup by walking up parent directories Nov 3, 2025
Copilot finished work on behalf of davidfowl November 3, 2025 15:59
}

// Stop if we've reached the AppHost's parent directory
if (string.Equals(currentDirectory, appHostParentDirectory, StringComparison.OrdinalIgnoreCase))
Copy link
Member

Choose a reason for hiding this comment

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

@copilot is this the correct way to compare directory paths?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Updated to use platform-aware comparison: StringComparison.OrdinalIgnoreCase on Windows (case-insensitive file system) and StringComparison.Ordinal on Unix (case-sensitive file system). This ensures correct path matching across platforms. Commit: 26930ab

Copilot finished work on behalf of eerhardt November 3, 2025 17:37
Copilot AI requested a review from eerhardt November 3, 2025 17:37
@eerhardt
Copy link
Member

eerhardt commented Nov 3, 2025

@copilot - this should also handle the case where the appDirectory isn't parented under the appHostParentDirectory. For example:

.venv
apphostparent/apphost.cs
someotherparent/pythonapp/myapp.py

When that happens, it should only look in the appDirectory.

Copy link
Contributor Author

Copilot AI commented Nov 3, 2025

@copilot - this should also handle the case where the appDirectory isn't parented under the appHostParentDirectory. For example:

...

Added check for this scenario. The code now:

  1. First checks if the app directory is under the AppHost's parent tree
  2. If not (different directory trees), only looks in the app directory itself - no walking up
  3. If yes (same tree), performs the walk-up logic stopping at AppHost's parent

This prevents walking up the entire directory structure when the app and AppHost are in separate trees. Commit: bf13f27

Copilot finished work on behalf of eerhardt November 3, 2025 19:07
Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

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

Just one more suggestion. Then the changes look good to me.

I didn't test this though, so @davidfowl you might want to give it a whirl.

@davidfowl davidfowl merged commit f5de144 into main Nov 4, 2025
582 of 585 checks passed
@davidfowl davidfowl deleted the copilot/add-venv-support-for-apphost branch November 4, 2025 07:18
@davidfowl
Copy link
Member

/backport to release/13.0

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

Started backporting to release/13.0: https://github.com/dotnet/aspire/actions/runs/19060887411

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants