Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for running python projects #4142

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

wmeints
Copy link

@wmeints wmeints commented May 10, 2024

This PR introduces support for running Python projects as part of an Aspire solution. I took the NodeJS extension as inspiration but had to add a couple of extra pieces of logic since Python is a lot less standardized when it comes to how projects are structured.

Initially I created this project: https://github.com/wmeints/aspire-python but I feel that this PR is a much more useful way to add support for Python. I think it's a great resolution for #2760.

Assumptions made by the extension

  • Your python project has a virtual environment located under .venv. Although you can change that.
  • You have a Dockerfile for publishing the project to test/acceptance/production environments.

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-components Issues pertaining to Aspire Component packages label May 10, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label May 10, 2024
Aspire.sln Outdated Show resolved Hide resolved
@mitchdenny
Copy link
Member

@davidfowl I've been thinking about things like Node.js (and now Python). I'm wondering if whether to make things easier for people we should create a boilerplate Dockerfile if one doesn't already exist. The idea being that it gives people a starting point.

So if someone does AddPython...) and points at a particular directory we'll drop down a Dockerfile and .dockerignore file if one doesn't already exist. Then the can tweak it from there customizing the base image etc.

@davidfowl
Copy link
Member

I don't think we should be writing files to disk using these APIs, but I like the idea that they would publish as a docker file by default. The publish operation would throw because it couldn't find one. That would instruct the user to add one for their language.

@wmeints
Copy link
Author

wmeints commented May 13, 2024

I can see I broke the build because I forgot to update the playground apphost. I will do that tomorrow morning (GMT+1)

Comment on lines +18 to +33
public void AddPythonProject_SetsResourcePropertiesCorrectly()
{
var pythonProjectDirectory = Path.Combine(s_playgroundDirectory, "script_only");
var appBuilder = DistributedApplication.CreateBuilder();

appBuilder.AddPythonProject("python", pythonProjectDirectory, "main.py");

var app = appBuilder.Build();
var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();
var executableResources = appModel.GetExecutableResources();

var pythonProjectResource = Assert.Single(executableResources);

Assert.Equal("python", pythonProjectResource.Name);
Assert.Equal(pythonProjectDirectory, pythonProjectResource.WorkingDirectory);
}
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Author

@wmeints wmeints May 16, 2024

Choose a reason for hiding this comment

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

@davidfowl I need a little advice on this. The python virtual env layout varies across platforms, on Windows there's a scripts directory while on linux and mac there's a bin directory for the executables. I could add OS detection and assume that the scripts/binaries are in the right spot. But I felt that it would be nicer to actually check on disk if the binaries are there.

Because of this choice I figured it would make sense to have local facts with an actual python environment instead of writing pure unit-tests.

I can make purer unit-tests by either: Making the assumption about the virtual env layout and not checking the disk. Or I can write temp dummy files to disk to make the unit-test pass.

What do you prefer? Or do you have other ideas?

Copy link
Member

Choose a reason for hiding this comment

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

What I'm doing with the incoming WithDockerfile(...) extension is creating a temp directory and dropping the minimum number of files I need in there. If the tests are going to actually spin up Python that is what you'd need to do.

Comment on lines +19 to +20
string[] allowedExtensions = [".exe", ".cmd", ".bat", ""];
string[] executableDirectories = ["bin", "Scripts"];
Copy link
Member

Choose a reason for hiding this comment

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

Filter this based on operating system?

/// <param name="executablePath">The path to the executable used to run the python project.</param>
/// <param name="projectDirectory">The path to the directory containing the python project.</param>
public class PythonProjectResource(string name, string executablePath, string projectDirectory)
: ExecutableResource(name, executablePath, projectDirectory), IResourceWithServiceDiscovery
Copy link
Member

Choose a reason for hiding this comment

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

Do we want this to implement IResourceWithServiceDiscovery?

/// </summary>
public static class PythonProjectResourceBuilderExtensions
{
/// <summary>
Copy link
Member

Choose a reason for hiding this comment

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

The <summary> should be a short one sentence thing. Move the rest into <remarks> (after <returns>).

Would be good to add an <example> as well for each of the extension methods.

private static readonly string s_playgroundDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "../../../../../playground/python/"));

[LocalOnlyFact("python")]
public void AddPythonProject_SetsResourcePropertiesCorrectly()
Copy link
Member

Choose a reason for hiding this comment

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

@radical heads up on this coming into the repo ... when we start running these tests in C# we are going to need Python available.

[LocalOnlyFact("python")]
public void AddPythonProject_SetsResourcePropertiesCorrectly()
{
var pythonProjectDirectory = Path.Combine(s_playgroundDirectory, "script_only");
Copy link
Member

Choose a reason for hiding this comment

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

You are going to need to use the testbuilder here (look at some of the other tests). Otherwise this will leak file watch handles.

AddProjectArguments(scriptPath, scriptArgs, context);
});

if(!string.IsNullOrEmpty(instrumentationExecutable))
Copy link
Member

Choose a reason for hiding this comment

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

nit: Formatting

/// <param name="scriptArgs">The arguments for the script.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<PythonProjectResource> AddPythonProject(
this IDistributedApplicationBuilder builder, string name, string projectDirectory, string scriptPath, string virtualEnvironmentPath = ".venv", params string[] scriptArgs)
Copy link
Member

Choose a reason for hiding this comment

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

Can you make the default value for virtualEnvironmentPath null and then check for it and replace it with the default inside the method. Also note the earlier comments I made about making <summary> shorter and more concise and adding a <remarks> section (where you can have your paragraphs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-components Issues pertaining to Aspire Component packages community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants