diff --git a/src/Aspire.Hosting.Python/PythonProjectResource.cs b/src/Aspire.Hosting.Python/PythonProjectResource.cs
index d50fa3b0dfe..0b00879b374 100644
--- a/src/Aspire.Hosting.Python/PythonProjectResource.cs
+++ b/src/Aspire.Hosting.Python/PythonProjectResource.cs
@@ -1,6 +1,8 @@
// 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;
@@ -12,7 +14,8 @@ namespace Aspire.Hosting.Python;
/// The path to the executable used to run the python project.
/// The path to the directory containing the python project.
public class PythonProjectResource(string name, string executablePath, string projectDirectory)
- : ExecutableResource(name, executablePath, projectDirectory), IResourceWithServiceDiscovery
+ : 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);
}
diff --git a/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs b/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs
index c1a04d78d7b..0e4734137b9 100644
--- a/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs
+++ b/src/Aspire.Hosting.Python/PythonProjectResourceBuilderExtensions.cs
@@ -60,6 +60,8 @@ public static class PythonProjectResourceBuilderExtensions
public static IResourceBuilder AddPythonProject(
this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, params string[] scriptArgs)
{
+ ArgumentNullException.ThrowIfNull(builder);
+
return builder.AddPythonProject(name, projectDirectory, scriptPath, ".venv", scriptArgs);
}
@@ -108,7 +110,12 @@ public static IResourceBuilder AddPythonProject(
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)
diff --git a/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs b/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs
new file mode 100644
index 00000000000..cd74a091324
--- /dev/null
+++ b/tests/Aspire.Hosting.Python.Tests/PythonPublicApiTests.cs
@@ -0,0 +1,270 @@
+// 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.Utils;
+using Xunit;
+
+namespace Aspire.Hosting.Python.Tests;
+
+public class PythonPublicApiTests
+{
+ [Fact]
+ public void CtorPythonProjectResourceShouldThrowWhenNameIsNull()
+ {
+ string name = null!;
+ const string executablePath = "/src/python";
+ const string projectDirectory = "/data/python";
+
+ var action = () => new PythonProjectResource(name, executablePath, projectDirectory);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(name), exception.ParamName);
+ }
+
+ [Fact]
+ public void CtorPythonProjectResourceShouldThrowWhenExecutablePathIsNull()
+ {
+ const string name = "Python";
+ string executablePath = null!;
+ const string projectDirectory = "/data/python";
+
+ var action = () => new PythonProjectResource(name, executablePath, projectDirectory);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(executablePath), exception.ParamName);
+ }
+
+ [Fact]
+ public void CtorPythonProjectResourceShouldThrowWhenProjectDirectoryIsNull()
+ {
+ const string name = "Python";
+ const string executablePath = "/src/python";
+ string projectDirectory = null!;
+
+ var action = () => new PythonProjectResource(name, executablePath, projectDirectory);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(projectDirectory), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectShouldThrowWhenBuilderIsNull()
+ {
+ IDistributedApplicationBuilder builder = null!;
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ string[] scriptArgs = ["--traces"];
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(builder), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectShouldThrowWhenNameIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ string name = null!;
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ string[] scriptArgs = ["--traces"];
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(name), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectShouldThrowWhenProjectDirectoryIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ string projectDirectory = null!;
+ const string scriptPath = "scripts";
+ string[] scriptArgs = ["--traces"];
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(projectDirectory), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectShouldThrowWhenScriptPathIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ string scriptPath = null!;
+ string[] scriptArgs = ["--traces"];
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(scriptPath), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectShouldThrowWhenScriptArgsIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ string[] scriptArgs = null!;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(scriptArgs), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenBuilderIsNull()
+ {
+ IDistributedApplicationBuilder builder = null!;
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ var virtualEnvironmentPath = ".venv";
+ string[] scriptArgs = ["--traces"]; ;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ virtualEnvironmentPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(builder), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenNameIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ string name = null!;
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ const string virtualEnvironmentPath = ".venv";
+ string[] scriptArgs = ["--traces"]; ;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ virtualEnvironmentPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(name), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenProjectDirectoryIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ string projectDirectory = null!;
+ const string scriptPath = "scripts";
+ const string virtualEnvironmentPath = ".venv";
+ string[] scriptArgs = ["--traces"]; ;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ virtualEnvironmentPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(projectDirectory), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptPathIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ string scriptPath = null!;
+ const string virtualEnvironmentPath = ".venv";
+ string[] scriptArgs = ["--traces"]; ;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ virtualEnvironmentPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(scriptPath), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenVirtualEnvironmentPathIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ string virtualEnvironmentPath = null!;
+ string[] scriptArgs = ["--traces"]; ;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ virtualEnvironmentPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(virtualEnvironmentPath), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddPythonProjectWithVirtualEnvironmentPathShouldThrowWhenScriptArgsIsNull()
+ {
+ var builder = TestDistributedApplicationBuilder.Create();
+ const string name = "Python";
+ const string projectDirectory = "/src/python";
+ const string scriptPath = "scripts";
+ const string virtualEnvironmentPath = ".venv";
+ string[] scriptArgs = null!;
+
+ var action = () => builder.AddPythonProject(
+ name,
+ projectDirectory,
+ scriptPath,
+ virtualEnvironmentPath,
+ scriptArgs);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(scriptArgs), exception.ParamName);
+ }
+}