Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a7bca82
Initial plan
Copilot Nov 4, 2025
2f7af80
Add WithPip and rename WithUvEnvironment to WithUv
Copilot Nov 4, 2025
b1898bf
Update WithUv to bootstrap Python and expose custom args
Copilot Nov 4, 2025
c4c5fdf
Unify WithPip and WithUv to follow Node.js pattern
Copilot Nov 4, 2025
fb8a550
Remove unused resource files (PythonPipInstallerResource, PythonUvEnv…
Copilot Nov 4, 2025
7b46d7b
Add support for detecting pyproject.toml
Copilot Nov 4, 2025
80b7a4b
Make pip support both pyproject.toml and requirements.txt
Copilot Nov 4, 2025
3784c78
Add venv creator resource for pip package manager
Copilot Nov 4, 2025
b76a598
Refactor Python package management based on feedback
Copilot Nov 4, 2025
b194bb5
Add createIfNotExists parameter to WithVirtualEnvironment
Copilot Nov 4, 2025
70b9e5e
Refactor venv creation to use BeforeStartEvent and be directory-based
Copilot Nov 4, 2025
b91ff7d
Simplify venv creation to use per-resource child resources
Copilot Nov 4, 2025
ab04107
Make venv creation independent of package manager
Copilot Nov 4, 2025
1289d59
WIP: Refactor wait dependencies to use BeforeStartEvent (needs fixing)
Copilot Nov 5, 2025
a5090ea
Implement feedback: Rename to SetupDependencies, only run in RunMode,…
Copilot Nov 5, 2025
82dc688
Fix failing tests - all 92 tests now passing
Copilot Nov 5, 2025
1a041c5
Use TryCreateResourceBuilder in RemoveVenvCreator
Copilot Nov 5, 2025
2354ed7
Rename AddPythonScript to AddPythonApp with OverloadResolutionPriority
Copilot Nov 5, 2025
97c264b
Fix AddPythonScript/AddPythonApp naming - remove obsolete, rename cor…
Copilot Nov 5, 2025
f519acf
Fix build.
eerhardt Nov 5, 2025
479b284
Remove AddPythonScript
eerhardt Nov 5, 2025
75e154c
Fix WithUv default args - remove incomplete --python flag
Copilot Nov 5, 2025
ab3e716
Fixed tests
davidfowl Nov 5, 2025
0237fb2
Minor PR feedback
eerhardt Nov 5, 2025
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
10 changes: 5 additions & 5 deletions playground/python/Python.AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

var builder = DistributedApplication.CreateBuilder(args);

builder.AddPythonScript("script-only", "../script_only", "main.py");
builder.AddPythonScript("instrumented-script", "../instrumented_script", "main.py");
builder.AddPythonApp("script-only", "../script_only", "main.py");
builder.AddPythonApp("instrumented-script", "../instrumented_script", "main.py");

builder.AddPythonModule("fastapi-app", "../module_only", "uvicorn")
.WithArgs("api:app", "--reload", "--host=0.0.0.0", "--port=8000")
.WithHttpEndpoint(targetPort: 8000)
.WithUvEnvironment();
.WithUv();

// Run the same app on another port using uvicorn directly
builder.AddPythonExecutable("fastapi-uvicorn-app", "../module_only", "uvicorn")
Expand All @@ -27,11 +27,11 @@
c.Args.Add("--port=8002");
})
.WithHttpEndpoint(targetPort: 8002)
.WithUvEnvironment();
.WithUv();

// Uvicorn app using the AddUvicornApp method
builder.AddUvicornApp("uvicorn-app", "../uvicorn_app", "app:app")
.WithUvEnvironment()
.WithUv()
.WithExternalHttpEndpoints();

#if !SKIP_DASHBOARD_REFERENCE
Expand Down
2 changes: 1 addition & 1 deletion playground/python/flask_app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This app is configured to run via the Python.AppHost project using `AddPythonMod
var flaskApp = builder.AddPythonModule("flask-app", "../flask_app", "flask")
.WithArgs("run", "--host=0.0.0.0", "--port=8000")
.WithHttpEndpoint(targetPort: 8000)
.WithUvEnvironment();
.WithUv();
```

## Local Development
Expand Down
523 changes: 426 additions & 97 deletions src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions src/Aspire.Hosting.Python/PythonEnvironmentAnnotation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@

namespace Aspire.Hosting.Python;

// Marker annotation to indicate a resource is for setting up a UV environment for a Python app.
// Marker annotation to indicate a resource is for setting up a Python environment.
internal class PythonEnvironmentAnnotation : IResourceAnnotation
{
public string? Version { get; set; }

public bool Uv { get; set; }

public VirtualEnvironment? VirtualEnvironment { get; set; }

/// <summary>
/// Gets or sets whether to automatically create the virtual environment if it doesn't exist.
/// Defaults to true.
/// </summary>
public bool CreateVenvIfNotExists { get; set; } = true;
}
21 changes: 21 additions & 0 deletions src/Aspire.Hosting.Python/PythonInstallCommandAnnotation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting.Python;

/// <summary>
/// Represents the annotation for the Python package manager's install command.
/// </summary>
/// <param name="args">
/// The command line arguments for the Python package manager's install command.
/// This includes the command itself (i.e. "install", "sync").
/// </param>
internal sealed class PythonInstallCommandAnnotation(string[] args) : IResourceAnnotation
{
/// <summary>
/// Gets the command-line arguments supplied to the Python package manager.
/// </summary>
public string[] Args { get; } = args;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
namespace Aspire.Hosting.Python;

/// <summary>
/// A resource that represents a UV environment setup task for a Python application.
/// A resource that represents a Python package installer task for a Python application.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="parent">The parent Python application resource.</param>
internal sealed class PythonUvEnvironmentResource(string name, PythonAppResource parent)
: ExecutableResource(name, "uv", parent.WorkingDirectory)
internal sealed class PythonInstallerResource(string name, PythonAppResource parent)
: ExecutableResource(name, "python", parent.WorkingDirectory)
{
}
17 changes: 17 additions & 0 deletions src/Aspire.Hosting.Python/PythonPackageInstallerAnnotation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting.Python;

/// <summary>
/// Represents an annotation for a Python installer resource.
/// </summary>
internal sealed class PythonPackageInstallerAnnotation(ExecutableResource installerResource) : IResourceAnnotation
{
/// <summary>
/// The instance of the Installer resource used.
/// </summary>
public ExecutableResource Resource { get; } = installerResource;
}
18 changes: 18 additions & 0 deletions src/Aspire.Hosting.Python/PythonPackageManagerAnnotation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting.Python;

/// <summary>
/// Represents the annotation for the Python package manager used in a resource.
/// </summary>
/// <param name="executableName">The name of the executable used to run the package manager.</param>
internal sealed class PythonPackageManagerAnnotation(string executableName) : IResourceAnnotation
{
/// <summary>
/// Gets the executable used to run the Python package manager.
/// </summary>
public string ExecutableName { get; } = executableName;
}
21 changes: 21 additions & 0 deletions src/Aspire.Hosting.Python/PythonVenvCreatorResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting.Python;

/// <summary>
/// A resource that represents a Python virtual environment creator task for a Python application.
/// </summary>
/// <param name="name">The name of the resource.</param>
/// <param name="parent">The parent Python application resource.</param>
/// <param name="venvPath">The path where the virtual environment should be created.</param>
internal sealed class PythonVenvCreatorResource(string name, PythonAppResource parent, string venvPath)
: ExecutableResource(name, "python", parent.WorkingDirectory)
{
/// <summary>
/// Gets the path where the virtual environment will be created.
/// </summary>
public string VenvPath => venvPath;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

#endif
var app = builder.AddUvicornApp("app", "./app", "main:app")
.WithUvEnvironment()
.WithUv()
.WithExternalHttpEndpoints()
#if UseRedisCache
.WithReference(cache)
Expand Down
Loading