diff --git a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Shipped.txt b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Shipped.txt index ecd6c08be..ddea663c9 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Shipped.txt +++ b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Shipped.txt @@ -1,5 +1,5 @@ #nullable enable Aspire.Hosting.ApplicationModel.UvicornAppResource -Aspire.Hosting.ApplicationModel.UvicornAppResource.UvicornAppResource(string! name, string! workingDirectory) -> void +Aspire.Hosting.ApplicationModel.UvicornAppResource.UvicornAppResource(string! name, string! executablePath, string! workingDirectory) -> void Aspire.Hosting.UvicornAppHostingExtension -static Aspire.Hosting.UvicornAppHostingExtension.AddUvicornApp(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! appName, string![]? args = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.UvicornAppHostingExtension.AddUvicornApp(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! appName, params string![]! args) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! diff --git a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Unshipped.txt b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Unshipped.txt index 4801f05ce..042c6e489 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Unshipped.txt +++ b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/PublicAPI.Unshipped.txt @@ -1,5 +1,5 @@ #nullable enable Aspire.Hosting.ApplicationModel.UvAppResource -Aspire.Hosting.ApplicationModel.UvAppResource.UvAppResource(string! name, string! workingDirectory) -> void +Aspire.Hosting.ApplicationModel.UvAppResource.UvAppResource(string! name, string! executablePath, string! workingDirectory) -> void Aspire.Hosting.UvAppHostingExtension static Aspire.Hosting.UvAppHostingExtension.AddUvApp(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! \ No newline at end of file diff --git a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppHostingExtension.cs index bf76cc2bb..dd3b4b1f3 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppHostingExtension.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppHostingExtension.cs @@ -50,28 +50,23 @@ private static IResourceBuilder AddUvApp(this IDistributedApplica : Path.Join(projectDirectory, virtualEnvironmentPath)); var instrumentationExecutable = virtualEnvironment.GetExecutable("opentelemetry-instrument"); - // var pythonExecutable = virtualEnvironment.GetRequiredExecutable("python"); - // var projectExecutable = instrumentationExecutable ?? pythonExecutable; + var projectExecutable = instrumentationExecutable ?? "uv"; - string[] allArgs = args is { Length: > 0 } - ? ["run", scriptPath, .. args] - : ["run", scriptPath]; + var projectResource = new UvAppResource(name, projectExecutable, projectDirectory); - var projectResource = new UvAppResource(name, projectDirectory); - - var resourceBuilder = builder.AddResource(projectResource) - .WithArgs(allArgs) - .WithArgs(context => + var resourceBuilder = builder.AddResource(projectResource).WithArgs(context => + { + // If the project is to be automatically instrumented, add the instrumentation executable arguments first. + if (!string.IsNullOrEmpty(instrumentationExecutable)) { - // If the project is to be automatically instrumented, add the instrumentation executable arguments first. - if (!string.IsNullOrEmpty(instrumentationExecutable)) - { - AddOpenTelemetryArguments(context); + AddOpenTelemetryArguments(context); + + // Add the uvicorn executable as the next argument so we can run the project. + context.Args.Add("uv"); + } - // // Add the python executable as the next argument so we can run the project. - // context.Args.Add(pythonExecutable!); - } - }); + AddProjectArguments(scriptPath, args, context); + }); if (!string.IsNullOrEmpty(instrumentationExecutable)) { @@ -85,6 +80,17 @@ private static IResourceBuilder AddUvApp(this IDistributedApplica return resourceBuilder; } + private static void AddProjectArguments(string scriptPath, string[] scriptArgs, CommandLineArgsCallbackContext context) + { + context.Args.Add("run"); + context.Args.Add(scriptPath); + + foreach (var arg in scriptArgs) + { + context.Args.Add(arg); + } + } + private static void AddOpenTelemetryArguments(CommandLineArgsCallbackContext context) { context.Args.Add("--traces_exporter"); diff --git a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppResource.cs b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppResource.cs index 467917eea..f1fc7ca91 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppResource.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvAppResource.cs @@ -6,9 +6,10 @@ namespace Aspire.Hosting.ApplicationModel; /// Represents a Uv application. /// /// The name of the resource. +/// The path to the executable used to run the python app. /// The working directory for uv. -public class UvAppResource(string name, string workingDirectory) - : PythonAppResource(name, "uv", workingDirectory), IResourceWithServiceDiscovery +public class UvAppResource(string name, string executablePath, string workingDirectory) + : PythonAppResource(name, executablePath, workingDirectory), IResourceWithServiceDiscovery { internal const string HttpEndpointName = "http"; } diff --git a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppHostingExtension.cs b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppHostingExtension.cs index c4742cabb..337af6de3 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppHostingExtension.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppHostingExtension.cs @@ -24,7 +24,7 @@ public static IResourceBuilder AddUvicornApp( [ResourceName] string name, string projectDirectory, string appName, - string[]? args = null) + params string[] args) { ArgumentNullException.ThrowIfNull(builder); @@ -36,7 +36,7 @@ private static IResourceBuilder AddUvicornApp(this IDistribu string projectDirectory, string appName, string virtualEnvironmentPath, - string[]? args = null) + params string[] args) { ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(appName); @@ -50,23 +50,23 @@ private static IResourceBuilder AddUvicornApp(this IDistribu : Path.Join(projectDirectory, virtualEnvironmentPath)); var instrumentationExecutable = virtualEnvironment.GetExecutable("opentelemetry-instrument"); + var projectExecutable = instrumentationExecutable ?? "uvicorn"; - string[] allArgs = args is { Length: > 0 } - ? [appName, .. args] - : [appName]; + var projectResource = new UvicornAppResource(name, projectExecutable, projectDirectory); - var projectResource = new UvicornAppResource(name, projectDirectory); + var resourceBuilder = builder.AddResource(projectResource).WithArgs(context => + { + // If the project is to be automatically instrumented, add the instrumentation executable arguments first. + if (!string.IsNullOrEmpty(instrumentationExecutable)) + { + AddOpenTelemetryArguments(context); + + // Add the uvicorn executable as the next argument so we can run the project. + context.Args.Add("uvicorn"); + } - var resourceBuilder = builder.AddResource(projectResource) - .WithArgs(allArgs) - .WithArgs(context => - { - // If the project is to be automatically instrumented, add the instrumentation executable arguments first. - if (!string.IsNullOrEmpty(instrumentationExecutable)) - { - AddOpenTelemetryArguments(context); - } - }); + AddProjectArguments(appName, args, context); + }); if (!string.IsNullOrEmpty(instrumentationExecutable)) { @@ -80,6 +80,16 @@ private static IResourceBuilder AddUvicornApp(this IDistribu return resourceBuilder; } + private static void AddProjectArguments(string scriptPath, string[] scriptArgs, CommandLineArgsCallbackContext context) + { + context.Args.Add(scriptPath); + + foreach (var arg in scriptArgs) + { + context.Args.Add(arg); + } + } + private static void AddOpenTelemetryArguments(CommandLineArgsCallbackContext context) { context.Args.Add("--traces_exporter"); diff --git a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppResource.cs b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppResource.cs index f5d83a389..d6ef4340a 100644 --- a/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppResource.cs +++ b/src/CommunityToolkit.Aspire.Hosting.Python.Extensions/UvicornAppResource.cs @@ -6,6 +6,7 @@ namespace Aspire.Hosting.ApplicationModel; /// Represents a Uvicorn application. /// /// The name of the resource. +/// The path to the executable used to run the python app. /// The working directory for uvicorn. -public class UvicornAppResource(string name, string workingDirectory) - : PythonAppResource(name, "uvicorn", workingDirectory), IResourceWithServiceDiscovery; \ No newline at end of file +public class UvicornAppResource(string name, string executablePath, string workingDirectory) + : PythonAppResource(name, executablePath, workingDirectory), IResourceWithServiceDiscovery; \ No newline at end of file