diff --git a/playground/python/Python.AppHost/Program.cs b/playground/python/Python.AppHost/Program.cs index 2444719637..ea51d15981 100644 --- a/playground/python/Python.AppHost/Program.cs +++ b/playground/python/Python.AppHost/Program.cs @@ -3,7 +3,7 @@ var builder = DistributedApplication.CreateBuilder(args); -builder.AddPythonProject("script-only", "../script_only", "main.py"); -builder.AddPythonProject("instrumented-script", "../instrumented_script", "main.py"); +builder.AddPythonApp("script-only", "../script_only", "main.py"); +builder.AddPythonApp("instrumented-script", "../instrumented_script", "main.py"); builder.Build().Run(); diff --git a/src/Aspire.Hosting.Python/PublicAPI.Shipped.txt b/src/Aspire.Hosting.Python/PublicAPI.Shipped.txt index 7dc5c58110..15000c10d9 100644 --- a/src/Aspire.Hosting.Python/PublicAPI.Shipped.txt +++ b/src/Aspire.Hosting.Python/PublicAPI.Shipped.txt @@ -1 +1,12 @@ #nullable enable +Aspire.Hosting.Python.PythonAppResource +Aspire.Hosting.Python.PythonAppResource.PythonAppResource(string! name, string! executablePath, string! projectDirectory) -> void +Aspire.Hosting.PythonAppResourceBuilderExtensions +static Aspire.Hosting.PythonAppResourceBuilderExtensions.AddPythonApp(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.PythonAppResourceBuilderExtensions.AddPythonApp(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, string! virtualEnvironmentPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! + +Aspire.Hosting.Python.PythonProjectResource +Aspire.Hosting.Python.PythonProjectResource.PythonProjectResource(string! name, string! executablePath, string! projectDirectory) -> void +Aspire.Hosting.PythonProjectResourceBuilderExtensions +static Aspire.Hosting.PythonProjectResourceBuilderExtensions.AddPythonProject(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.PythonProjectResourceBuilderExtensions.AddPythonProject(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, string! virtualEnvironmentPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! \ No newline at end of file diff --git a/src/Aspire.Hosting.Python/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Python/PublicAPI.Unshipped.txt index ea5d8f1640..815c92006a 100644 --- a/src/Aspire.Hosting.Python/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Python/PublicAPI.Unshipped.txt @@ -1,6 +1 @@ -#nullable enable -Aspire.Hosting.Python.PythonProjectResource -Aspire.Hosting.Python.PythonProjectResource.PythonProjectResource(string! name, string! executablePath, string! projectDirectory) -> void -Aspire.Hosting.PythonProjectResourceBuilderExtensions -static Aspire.Hosting.PythonProjectResourceBuilderExtensions.AddPythonProject(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.PythonProjectResourceBuilderExtensions.AddPythonProject(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, string! projectDirectory, string! scriptPath, string! virtualEnvironmentPath, params string![]! scriptArgs) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +#nullable enable \ No newline at end of file diff --git a/src/Aspire.Hosting.Python/PythonAppResource.cs b/src/Aspire.Hosting.Python/PythonAppResource.cs new file mode 100644 index 0000000000..86e11579d0 --- /dev/null +++ b/src/Aspire.Hosting.Python/PythonAppResource.cs @@ -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 System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using Aspire.Hosting.ApplicationModel; + +namespace Aspire.Hosting.Python; + +/// +/// A resource that represents a python executible or app. +/// +/// The name of the resource. +/// The path to the executable used to run the python app. +/// The path to the directory containing the python app. +public class PythonAppResource(string name, string executablePath, string projectDirectory) + : ExecutableResource(ThrowIfNull(name), ThrowIfNull(executablePath), ThrowIfNull(projectDirectory)), IResourceWithServiceDiscovery +{ + private static string ThrowIfNull([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) + => argument ?? throw new ArgumentNullException(paramName); +} \ No newline at end of file diff --git a/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs b/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs new file mode 100644 index 0000000000..b726fff477 --- /dev/null +++ b/src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs @@ -0,0 +1,180 @@ +// 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; +using Aspire.Hosting.Python; +using Aspire.Hosting.Utils; + +namespace Aspire.Hosting; + +/// +/// Provides extension methods for adding Python applications to an . +/// +public static class PythonAppResourceBuilderExtensions +{ + /// + /// Adds a python application with a virtual environment to the application model. + /// + /// The to add the resource to. + /// The name of the resource. + /// The path to the directory containing the python app files. + /// The path to the script relative to the project directory to run. + /// The arguments for the script. + /// A reference to the . + /// + /// + /// The virtual environment must be initialized before running the project. By default the virtual environment folder is expected + /// to be named .venv and be located in the project directory. If the virtual environment is located in a different directory + /// this default can be specified by using the + /// overload of this method. + /// + /// + /// The virtual environment is setup individually for each project to allow each project to use a different version of + /// Python and dependencies. To setup a virtual environment use the python -m venv .venv command in the project + /// directory. This will create a virtual environment in the .venv directory. + /// + /// + /// To restore dependencies in the virtual environment first activate the environment by executing the activation + /// script and then use the pip install -r requirements.txt command to restore dependencies. + /// + /// + /// To receive traces, logs, and metrics from the python project in the dashboard, the project must be instrumented with OpenTelemetry. + /// You can instrument your project by adding the opentelemetry-distro, and opentelemetry-exporter-otlp to + /// your Python project. + /// + /// + /// + /// Add a python app or executible to the application model. In this example the python code entry point is located in the PythonProject directory + /// if this path is relative then it is assumed to be relative to the AppHost directory, and the virtual enviroment path if relative + /// is relative to the project directory. In the example below, if the app host directory is $HOME/repos/MyApp/src/MyApp.AppHost then + /// the ProjectPath would be $HOME/repos/MyApp/src/MyApp.AppHost/PythonProject and the virtual environment path (defaulted) would + /// be $HOME/repos/MyApp/src/MyApp.AppHost/PythonProject/.venv. + /// + /// var builder = DistributedApplication.CreateBuilder(args); + /// + /// builder.AddPythonApp("python-project", "PythonProject", "main.py"); + /// + /// builder.Build().Run(); + /// + /// + public static IResourceBuilder AddPythonApp( + this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, params string[] scriptArgs) + { + ArgumentNullException.ThrowIfNull(builder); + + return builder.AddPythonApp(name, projectDirectory, scriptPath, ".venv", scriptArgs); + } + + /// + /// Adds a python application with a virtual environment to the application model. + /// + /// The to add the resource to. + /// The name of the resource. + /// The path to the directory containing the python project files. + /// The path to the script relative to the project directory to run. + /// Path to the virtual environment. + /// The arguments for the script. + /// A reference to the . + /// + /// + /// The virtual environment is setup individually for each project to allow each project to use a different version of + /// Python and dependencies. To setup a virtual environment use the python -m venv .venv command in the project + /// directory. This will create a virtual environment in the .venv directory (where .venv is the name of your + /// virtual environment directory). + /// + /// + /// To restore dependencies in the virtual environment first activate the environment by executing the activation + /// script and then use the pip install -r requirements.txt command to restore dependencies. + /// + /// + /// To receive traces, logs, and metrics from the python project in the dashboard, the project must be instrumented with OpenTelemetry. + /// You can instrument your project by adding the opentelemetry-distro, and opentelemetry-exporter-otlp to + /// your Python project. + /// + /// + /// + /// Add a python app or executible to the application model. In this example the python code is located in the PythonProject directory + /// if this path is relative then it is assumed to be relative to the AppHost directory, and the virtual enviroment path if relative + /// is relative to the project directory. In the example below, if the app host directory is $HOME/repos/MyApp/src/MyApp.AppHost then + /// the ProjectPath would be $HOME/repos/MyApp/src/MyApp.AppHost/PythonProject and the virtual environment path (defaulted) would + /// be $HOME/repos/MyApp/src/MyApp.AppHost/PythonProject/.venv. + /// + /// var builder = DistributedApplication.CreateBuilder(args); + /// + /// builder.AddPythonApp("python-project", "PythonProject", "main.py"); + /// + /// builder.Build().Run(); + /// + /// + public static IResourceBuilder AddPythonApp( + this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, + string virtualEnvironmentPath, params string[] scriptArgs) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(name); + ArgumentNullException.ThrowIfNull(projectDirectory); + ArgumentNullException.ThrowIfNull(scriptPath); + ArgumentNullException.ThrowIfNull(virtualEnvironmentPath); + ArgumentNullException.ThrowIfNull(scriptArgs); + + projectDirectory = PathNormalizer.NormalizePathForCurrentPlatform(Path.Combine(builder.AppHostDirectory, projectDirectory)); + var virtualEnvironment = new VirtualEnvironment(Path.IsPathRooted(virtualEnvironmentPath) + ? virtualEnvironmentPath + : Path.Join(projectDirectory, virtualEnvironmentPath)); + + var instrumentationExecutable = virtualEnvironment.GetExecutable("opentelemetry-instrument"); + var pythonExecutable = virtualEnvironment.GetRequiredExecutable("python"); + var projectExecutable = instrumentationExecutable ?? pythonExecutable; + + var projectResource = new PythonAppResource(name, projectExecutable, 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 python executable as the next argument so we can run the project. + context.Args.Add(pythonExecutable!); + } + + AddProjectArguments(scriptPath, scriptArgs, context); + }); + + if (!string.IsNullOrEmpty(instrumentationExecutable)) + { + resourceBuilder.WithOtlpExporter(); + + // Make sure to attach the logging instrumentation setting, so we can capture logs. + // Without this you'll need to configure logging yourself. Which is kind of a pain. + resourceBuilder.WithEnvironment("OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED", "true"); + } + + resourceBuilder.PublishAsDockerFile(); + + 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"); + context.Args.Add("otlp"); + + context.Args.Add("--logs_exporter"); + context.Args.Add("console,otlp"); + + context.Args.Add("--metrics_exporter"); + context.Args.Add("otlp"); + } +} \ No newline at end of file diff --git a/src/Aspire.Hosting.Python/PythonProjectResource.cs b/src/Aspire.Hosting.Python/PythonProjectResource.cs index 0b00879b37..bf419223e9 100644 --- a/src/Aspire.Hosting.Python/PythonProjectResource.cs +++ b/src/Aspire.Hosting.Python/PythonProjectResource.cs @@ -8,11 +8,12 @@ namespace Aspire.Hosting.Python; /// -/// A resource that represents a Python project. +/// This method is retained only for compatibility. /// /// The name of the resource. /// The path to the executable used to run the python project. /// The path to the directory containing the python project. +[Obsolete("PythonProjectResource is deprecated. Please use PythonAppResource instead.")] public class PythonProjectResource(string name, string executablePath, string projectDirectory) : ExecutableResource(ThrowIfNull(name), ThrowIfNull(executablePath), ThrowIfNull(projectDirectory)), IResourceWithServiceDiscovery { diff --git a/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs b/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs index 0e4734137b..6ddb927da0 100644 --- a/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs +++ b/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs @@ -8,12 +8,13 @@ namespace Aspire.Hosting; /// -/// Provides extension methods for adding Python applications to an . +/// This class is retained only for compatibility. /// +[Obsolete("PythonProjectResource is deprecated. Please use PythonAppResource instead.")] public static class PythonProjectResourceBuilderExtensions { /// - /// Adds a python application with a virtual environment to the application model. + /// This method is retained only for compatibility. /// /// The to add the resource to. /// The name of the resource. @@ -57,6 +58,7 @@ public static class PythonProjectResourceBuilderExtensions /// builder.Build().Run(); /// /// + [Obsolete("AddPythonProject is deprecated. Please use AddPythonApp instead.")] public static IResourceBuilder AddPythonProject( this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, params string[] scriptArgs) { @@ -66,7 +68,7 @@ public static IResourceBuilder AddPythonProject( } /// - /// Adds a python application with a virtual environment to the application model. + /// This method is retained only for compatibility. /// /// The to add the resource to. /// The name of the resource. @@ -106,6 +108,7 @@ public static IResourceBuilder AddPythonProject( /// builder.Build().Run(); /// /// + [Obsolete("AddPythonProject is deprecated. Please use AddPythonApp instead.")] public static IResourceBuilder AddPythonProject( this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, string virtualEnvironmentPath, params string[] scriptArgs) diff --git a/src/Aspire.Hosting.Python/VirtualEnvironment.cs b/src/Aspire.Hosting.Python/VirtualEnvironment.cs index f063883cb4..877762b8bd 100644 --- a/src/Aspire.Hosting.Python/VirtualEnvironment.cs +++ b/src/Aspire.Hosting.Python/VirtualEnvironment.cs @@ -4,9 +4,9 @@ namespace Aspire.Hosting.Python; /// -/// Handles location of files within the virtual environment of a python project. +/// Handles location of files within the virtual environment of a python app. /// -/// The path to the directory containing the python project files. +/// The path to the directory containing the python app files. internal sealed class VirtualEnvironment(string virtualEnvironmentPath) { /// diff --git a/tests/Aspire.Hosting.Python.Tests/AddPythonProjectTests.cs b/tests/Aspire.Hosting.Python.Tests/AddPythonAppTests.cs similarity index 92% rename from tests/Aspire.Hosting.Python.Tests/AddPythonProjectTests.cs rename to tests/Aspire.Hosting.Python.Tests/AddPythonAppTests.cs index f2e41189fb..54d50b2f15 100644 --- a/tests/Aspire.Hosting.Python.Tests/AddPythonProjectTests.cs +++ b/tests/Aspire.Hosting.Python.Tests/AddPythonAppTests.cs @@ -13,11 +13,11 @@ namespace Aspire.Hosting.Python.Tests; -public class AddPythonProjectTests(ITestOutputHelper outputHelper) +public class AddPythonAppTests(ITestOutputHelper outputHelper) { [Fact] [RequiresTools(["python"])] - public async Task AddPythonProjectProducesDockerfileResourceInManifest() + public async Task AddPythonAppProducesDockerfileResourceInManifest() { var (projectDirectory, pythonExecutable, scriptName) = CreateTempPythonProject(outputHelper); @@ -29,7 +29,7 @@ public async Task AddPythonProjectProducesDockerfileResourceInManifest() options.Args = ["--publisher", "manifest", "--output-path", manifestPath]; }, outputHelper); - var pyproj = builder.AddPythonProject("pyproj", projectDirectory, scriptName); + var pyproj = builder.AddPythonApp("pyproj", projectDirectory, scriptName); var manifest = await ManifestUtils.GetManifest(pyproj.Resource, manifestDirectory: projectDirectory); var expectedManifest = $$""" @@ -59,7 +59,7 @@ public async Task AddInstrumentedPythonProjectProducesDockerfileResourceInManife options.Args = ["--publisher", "manifest", "--output-path", manifestPath]; }, outputHelper); - var pyproj = builder.AddPythonProject("pyproj", projectDirectory, scriptName); + var pyproj = builder.AddPythonApp("pyproj", projectDirectory, scriptName); var manifest = await ManifestUtils.GetManifest(pyproj.Resource, manifestDirectory: projectDirectory); var expectedManifest = $$""" @@ -88,7 +88,7 @@ public async Task PythonResourceFinishesSuccessfully() var (projectDirectory, _, scriptName) = CreateTempPythonProject(outputHelper); using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(outputHelper); - builder.AddPythonProject("pyproj", projectDirectory, scriptName); + builder.AddPythonApp("pyproj", projectDirectory, scriptName); using var app = builder.Build(); @@ -115,7 +115,7 @@ public async Task PythonResourceSupportsWithReference() var externalResource = builder.AddConnectionString("connectionString"); builder.Configuration["ConnectionStrings:connectionString"] = "test"; - var pyproj = builder.AddPythonProject("pyproj", projectDirectory, scriptName) + var pyproj = builder.AddPythonApp("pyproj", projectDirectory, scriptName) .WithReference(externalResource); var environmentVariables = await pyproj.Resource.GetEnvironmentVariableValuesAsync(DistributedApplicationOperation.Run); @@ -128,13 +128,13 @@ public async Task PythonResourceSupportsWithReference() [Fact] [RequiresTools(["python"])] - public async Task AddPythonProject_SetsResourcePropertiesCorrectly() + public async Task AddPythonApp_SetsResourcePropertiesCorrectly() { using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(outputHelper); var (projectDirectory, pythonExecutable, scriptName) = CreateTempPythonProject(outputHelper); - builder.AddPythonProject("pythonProject", projectDirectory, scriptName); + builder.AddPythonApp("pythonProject", projectDirectory, scriptName); var app = builder.Build(); var appModel = app.Services.GetRequiredService(); @@ -164,13 +164,13 @@ public async Task AddPythonProject_SetsResourcePropertiesCorrectly() [Fact] [RequiresTools(["python"])] - public async Task AddPythonProjectWithInstrumentation_SwitchesExecutableToInstrumentationExecutable() + public async Task AddPythonAppWithInstrumentation_SwitchesExecutableToInstrumentationExecutable() { using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(outputHelper); var (projectDirectory, pythonExecutable, scriptName) = CreateTempPythonProject(outputHelper, instrument: true); - builder.AddPythonProject("pythonProject", projectDirectory, scriptName, virtualEnvironmentPath: ".venv"); + builder.AddPythonApp("pythonProject", projectDirectory, scriptName, virtualEnvironmentPath: ".venv"); var app = builder.Build(); var appModel = app.Services.GetRequiredService(); @@ -203,13 +203,13 @@ public async Task AddPythonProjectWithInstrumentation_SwitchesExecutableToInstru [Fact] [RequiresTools(["python"])] - public async Task AddPythonProjectWithScriptArgs_IncludesTheArguments() + public async Task AddPythonAppWithScriptArgs_IncludesTheArguments() { using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(outputHelper); var (projectDirectory, pythonExecutable, scriptName) = CreateTempPythonProject(outputHelper); - builder.AddPythonProject("pythonProject", projectDirectory, scriptName, scriptArgs: "test"); + builder.AddPythonApp("pythonProject", projectDirectory, scriptName, scriptArgs: "test"); var app = builder.Build(); var appModel = app.Services.GetRequiredService(); diff --git a/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs b/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs index cd74a09132..8c70c549a5 100644 --- a/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs +++ b/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs @@ -9,46 +9,46 @@ namespace Aspire.Hosting.Python.Tests; public class PythonPublicApiTests { [Fact] - public void CtorPythonProjectResourceShouldThrowWhenNameIsNull() + public void CtorPythonAppResourceShouldThrowWhenNameIsNull() { string name = null!; const string executablePath = "/src/python"; const string projectDirectory = "/data/python"; - var action = () => new PythonProjectResource(name, executablePath, projectDirectory); + var action = () => new PythonAppResource(name, executablePath, projectDirectory); var exception = Assert.Throws(action); Assert.Equal(nameof(name), exception.ParamName); } [Fact] - public void CtorPythonProjectResourceShouldThrowWhenExecutablePathIsNull() + public void CtorPythonAppResourceShouldThrowWhenExecutablePathIsNull() { const string name = "Python"; string executablePath = null!; const string projectDirectory = "/data/python"; - var action = () => new PythonProjectResource(name, executablePath, projectDirectory); + var action = () => new PythonAppResource(name, executablePath, projectDirectory); var exception = Assert.Throws(action); Assert.Equal(nameof(executablePath), exception.ParamName); } [Fact] - public void CtorPythonProjectResourceShouldThrowWhenProjectDirectoryIsNull() + public void CtorPythonAppResourceShouldThrowWhenProjectDirectoryIsNull() { const string name = "Python"; const string executablePath = "/src/python"; string projectDirectory = null!; - var action = () => new PythonProjectResource(name, executablePath, projectDirectory); + var action = () => new PythonAppResource(name, executablePath, projectDirectory); var exception = Assert.Throws(action); Assert.Equal(nameof(projectDirectory), exception.ParamName); } [Fact] - public void AddPythonProjectShouldThrowWhenBuilderIsNull() + public void AddPythonAppShouldThrowWhenBuilderIsNull() { IDistributedApplicationBuilder builder = null!; const string name = "Python"; @@ -56,7 +56,7 @@ public void AddPythonProjectShouldThrowWhenBuilderIsNull() const string scriptPath = "scripts"; string[] scriptArgs = ["--traces"]; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -67,7 +67,7 @@ public void AddPythonProjectShouldThrowWhenBuilderIsNull() } [Fact] - public void AddPythonProjectShouldThrowWhenNameIsNull() + public void AddPythonAppShouldThrowWhenNameIsNull() { var builder = TestDistributedApplicationBuilder.Create(); string name = null!; @@ -75,7 +75,7 @@ public void AddPythonProjectShouldThrowWhenNameIsNull() const string scriptPath = "scripts"; string[] scriptArgs = ["--traces"]; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -86,7 +86,7 @@ public void AddPythonProjectShouldThrowWhenNameIsNull() } [Fact] - public void AddPythonProjectShouldThrowWhenProjectDirectoryIsNull() + public void AddPythonAppShouldThrowWhenProjectDirectoryIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -94,7 +94,7 @@ public void AddPythonProjectShouldThrowWhenProjectDirectoryIsNull() const string scriptPath = "scripts"; string[] scriptArgs = ["--traces"]; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -105,7 +105,7 @@ public void AddPythonProjectShouldThrowWhenProjectDirectoryIsNull() } [Fact] - public void AddPythonProjectShouldThrowWhenScriptPathIsNull() + public void AddPythonAppShouldThrowWhenScriptPathIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -113,7 +113,7 @@ public void AddPythonProjectShouldThrowWhenScriptPathIsNull() string scriptPath = null!; string[] scriptArgs = ["--traces"]; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -124,7 +124,7 @@ public void AddPythonProjectShouldThrowWhenScriptPathIsNull() } [Fact] - public void AddPythonProjectShouldThrowWhenScriptArgsIsNull() + public void AddPythonAppShouldThrowWhenScriptArgsIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -132,7 +132,7 @@ public void AddPythonProjectShouldThrowWhenScriptArgsIsNull() const string scriptPath = "scripts"; string[] scriptArgs = null!; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -143,7 +143,7 @@ public void AddPythonProjectShouldThrowWhenScriptArgsIsNull() } [Fact] - public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenBuilderIsNull() + public void AddPythonAppWithVirtualEnvironmentPathShouldThrowWhenBuilderIsNull() { IDistributedApplicationBuilder builder = null!; const string name = "Python"; @@ -152,7 +152,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenBuilderIsNu var virtualEnvironmentPath = ".venv"; string[] scriptArgs = ["--traces"]; ; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -164,7 +164,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenBuilderIsNu } [Fact] - public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenNameIsNull() + public void AddPythonAppWithVirtualEnvironmentPathShouldThrowWhenNameIsNull() { var builder = TestDistributedApplicationBuilder.Create(); string name = null!; @@ -173,7 +173,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenNameIsNull( const string virtualEnvironmentPath = ".venv"; string[] scriptArgs = ["--traces"]; ; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -185,7 +185,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenNameIsNull( } [Fact] - public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenProjectDirectoryIsNull() + public void AddPythonAppWithVirtualEnvironmentPathShouldThrowWhenProjectDirectoryIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -194,7 +194,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenProjectDire const string virtualEnvironmentPath = ".venv"; string[] scriptArgs = ["--traces"]; ; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -206,7 +206,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenProjectDire } [Fact] - public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptPathIsNull() + public void AddPythonAppWithVirtualEnvironmentPathShouldThrowWhenScriptPathIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -215,7 +215,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptPathI const string virtualEnvironmentPath = ".venv"; string[] scriptArgs = ["--traces"]; ; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -227,7 +227,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptPathI } [Fact] - public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenVirtualEnvironmentPathIsNull() + public void AddPythonAppWithVirtualEnvironmentPathShouldThrowWhenVirtualEnvironmentPathIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -236,7 +236,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenVirtualEnvi string virtualEnvironmentPath = null!; string[] scriptArgs = ["--traces"]; ; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath, @@ -248,7 +248,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenVirtualEnvi } [Fact] - public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptArgsIsNull() + public void AddPythonAppWithVirtualEnvironmentPathShouldThrowWhenScriptArgsIsNull() { var builder = TestDistributedApplicationBuilder.Create(); const string name = "Python"; @@ -257,7 +257,7 @@ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptArgsI const string virtualEnvironmentPath = ".venv"; string[] scriptArgs = null!; - var action = () => builder.AddPythonProject( + var action = () => builder.AddPythonApp( name, projectDirectory, scriptPath,