PythonSharp 1.0.2
dotnet add package PythonSharp --version 1.0.2
NuGet\Install-Package PythonSharp -Version 1.0.2
<PackageReference Include="PythonSharp" Version="1.0.2" />
paket add PythonSharp --version 1.0.2
#r "nuget: PythonSharp, 1.0.2"
// Install PythonSharp as a Cake Addin #addin nuget:?package=PythonSharp&version=1.0.2 // Install PythonSharp as a Cake Tool #tool nuget:?package=PythonSharp&version=1.0.2
<img src="https://github.com/jchristn/PythonSharp/blob/main/Assets/logo.png?raw=true" data-canonical-src="https://github.com/jchristn/PythonSharp/blob/main/Assets/logo.png?raw=true" width="128" height="128" />
PythonSharp
PythonSharp is a simple library for invoking Python scripts from C# and retrieving their return value.
Why not just use pythonnet? Pythonnet is a fantastic, useful, and well-written library, managed and maintained by an excellent community. However, it is challenged in being able to support multiple concurrent virtual environments. Further, pythonnet provides near seamless integration with the .NET CLR, whereas PythonSharp is a wrapper library that invokes Python scripts using the shell. To summarize, you should use pythonnet in most cases, but consider PythonSharp when you need to support multiple virtual environments concurrently.
Help, Feedback, Contribute
If you have any issues or feedback, please file an issue here in Github. We'd love to have you help by contributing code for new features, optimization to the existing codebase, ideas for future releases, or fixes!
New in v1.0.x
- Initial release
Example Project
Refer to the Test
project for exercising the library. Create one instance of the PythonRunner
class for each separate invocation.
using PythonSharp;
// Create the environment object.
PythonEnvironment env = new PythonEnvironment();
// Set the base executable and pip command.
env.PythonExecutable = "C:\\Program Files\\Python312\\python.exe";
env.PipCommand = "C:\\Program Files\\Python312\\Scripts\\pip.exe";
// Set up the virtual environment, or skip. If it does not exist, PythonSharp will create it.
env.VirtualEnvironmentPath = "./myscripts/venv/";
// Define path to the directory containing your script.
env.ScriptPath = "./myscripts/";
// Specify the requirements.txt file, or skip.
env.RequirementsFile = "./myscripts/requirements.txt";
// Create the script runner.
PythonRunner runner = new PythonRunner(env);
PythonResult result = runner.RunScript("script.py", "{ \"hello\": \"world\" }");
// {
// "GUID": "[GUID]", // Unique identifier for the execution
// "Success": true, // Success or failure
// "CommandResult": 0, // Result of the shell command to run the script
// "ConsoleOutput": "[Console messages here]", // Console output encountered during execution
// "ErrorOutput": "[Error messages here]", // Error output encountered during execution
// "Data": "{ \"hello\": \"world\" }"; // Data returned from the script
// "Exception": null // Exception, if any
// }
How Does it Work?
PythonSharp uses the Shelli library to invoke shell commands. Under the hood, shell commands are issued when necessary to create virtual environments, install requirements (inside or outside of a virtual environment), enter and exit virtual environments, and to invoke scripts.
User scripts should be implemented with a def process(req):
method. The input req
is a dictionary, and the output of this method must also be a dictionary.
Internally, a Guid
is assigned for each invocation of a script. This serves as an identifier for temporary files that are created during execution:
- A wrapper script, which encapsulates the user script
- An output file, containing a JSON representation of the dictionary response from the user script
The wrapper script is lightweight, and only serves to deserialize the input data supplied to runner.RunScript
into a dictionary, and, to serialize the output data from the user function into a JSON object. The user script is imported into the wrapper script, and saved as a temporary file called [Guid].py
. This file is deleted after execution.
The result value is stored in a file called [Guid].resp
on the filesystem, and PythonSharp will read this file to obtain the results and then delete it.
The wrapper script, with a simple def process(req):
integrated within, looks as follows when calling runner.RunScript("script.py", "{ \"hello\": \"world\" }");
:
import json
# Begin user code
def process(req):
print("Hello from user code!")
return req
# End user code
_req_obj = json.loads('{ "hello": "world" }')
_resp_obj = process(_req_obj)
_out_file = open('9f786ef-7690-4024-8ec0-e5d699246527.resp', 'w')
_out_file.write(json.dumps(_resp_obj))
User Script Requirements
- User scripts must implement a method
def process(req):
as the entrypoint for their code - The input variable
req
to this method is a dictionary (deserialized from the JSON string supplied when invokingrunner.RunScript
) - The
def process(req):
method should return a dictionary
Version History
Refer to CHANGELOG.md for version history.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net8.0
- RestWrapper (>= 3.0.20)
- Shelli (>= 2.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial release