PySharp.Interop
1.0.1
dotnet add package PySharp.Interop --version 1.0.1
NuGet\Install-Package PySharp.Interop -Version 1.0.1
<PackageReference Include="PySharp.Interop" Version="1.0.1" />
<PackageVersion Include="PySharp.Interop" Version="1.0.1" />
<PackageReference Include="PySharp.Interop" />
paket add PySharp.Interop --version 1.0.1
#r "nuget: PySharp.Interop, 1.0.1"
#:package PySharp.Interop@1.0.1
#addin nuget:?package=PySharp.Interop&version=1.0.1
#tool nuget:?package=PySharp.Interop&version=1.0.1
PySharp ๐โก
Type-safe Python interop for C# โ Call Python like it's native code.
PySharp lets you define C# interfaces that map directly to Python classes and modules. No boilerplate, no string-based method calls, no runtime surprises. Just clean, strongly-typed code.
[PyClass("math_ops")]
public interface IMathOps
{
[PyMethod("add")]
int Add(int a, int b);
[PyMethod("mul")]
Task<int> MultiplyAsync(int a, int b);
}
// Use it like any C# interface
var math = PyWrapperFactory.Create<IMathOps>();
Console.WriteLine(math.Add(3, 5)); // 8
Console.WriteLine(await math.MultiplyAsync(6, 7)); // 42
โจ Features
- Type-Safe โ Define interfaces with proper C# types. Get compile-time safety and IntelliSense.
- Attribute-Based Mapping โ Use
[PyClass],[PyModule],[PyMethod], and[PyClassMethod]to declaratively map C# to Python. - Async Support โ Return
Task<T>from any method for non-blocking Python calls. - Direct Module Access โ Call static/class methods on Python modules without writing wrapper classes.
- Object Handles โ Pass complex Python objects (like ML models) between C# methods with
PyObjectHandle. - Auto-Detection โ Automatically finds Python installation on Windows, macOS, and Linux.
๐ฆ Installation
Prerequisites
- .NET Standard 2.1 compatible framework (.NET Core 3.0+, .NET 5+, .NET Framework 4.8+ with .NET Standard 2.1 support)
- Python 3.7โ3.13 installed on your system
NuGet Package
Install via Package Manager Console:
Install-Package PySharp.Interop
Or via .NET CLI:
dotnet add package PySharp.Interop
Or add to your .csproj:
<PackageReference Include="PySharp.Interop" Version="1.0.0" />
Clone & Build
git clone https://github.com/mertyildiz41/PySharp.git
cd PySharp
dotnet build
๐ Quick Start
1. Create a Python Module
# python/math_ops.py
class math_ops:
def add(self, a, b):
return a + b
def mul(self, a, b):
return a * b
2. Define a C# Interface
using PySharp.Attributes;
[PyClass("math_ops")]
public interface IMathOps
{
[PyMethod("add")]
int Add(int a, int b);
[PyMethod("mul")]
int Multiply(int a, int b);
[PyMethod("mul")]
Task<int> MultiplyAsync(int a, int b);
}
3. Use It
using PySharp.Core;
// Initialize Python engine (auto-detects Python installation)
PythonEngineInitializer.Initialize(extraPaths: new[] { "./python" });
// Create a typed wrapper
var mathOps = PyWrapperFactory.Create<IMathOps>();
Console.WriteLine(mathOps.Add(3, 5)); // 8
Console.WriteLine(mathOps.Multiply(2, 4)); // 8
Console.WriteLine(await mathOps.MultiplyAsync(6, 7)); // 42
๐ API Reference
Attributes
[PyClass(className, moduleName?)]
Maps a C# interface to a Python class. An instance of the class is created automatically.
| Parameter | Description |
|---|---|
className |
Name of the Python class to instantiate |
moduleName |
(Optional) Module name. Defaults to className |
[PyClass("Calculator", "my_math_module")]
public interface ICalculator { ... }
[PyModule(moduleName)]
Maps a C# interface directly to a Python module for calling static/class methods.
[PyModule("transformers")]
public interface ITransformers { ... }
[PyMethod(methodName)]
Maps a C# method to a Python instance method.
[PyMethod("calculate_sum")]
int Sum(int a, int b);
[PyClassMethod(className, methodName)]
Maps a C# method to a Python class/static method. Use with [PyModule].
[PyClassMethod("AutoModelForCausalLM", "from_pretrained")]
PyObjectHandle LoadModel(string modelName);
๐ค Advanced: Direct Module Access (LLM Example)
PySharp can call Python libraries directly without writing Python wrapper code. Here's an example using HuggingFace Transformers:
[PyModule("transformers")]
public interface ITransformers
{
[PyClassMethod("AutoModelForCausalLM", "from_pretrained")]
PyObjectHandle LoadModel(string modelName);
[PyClassMethod("AutoModelForCausalLM", "from_pretrained")]
Task<PyObjectHandle> LoadModelAsync(string modelName);
[PyClassMethod("AutoTokenizer", "from_pretrained")]
PyObjectHandle LoadTokenizer(string modelName);
}
[PyModule("torch")]
public interface ITorch
{
[PyClassMethod("cuda", "is_available")]
bool IsCudaAvailable();
}
Using PyObjectHandle
PyObjectHandle lets you store and pass Python objects between method calls:
var transformers = PyWrapperFactory.Create<ITransformers>();
// Load model and tokenizer
var model = await transformers.LoadModelAsync("Qwen/Qwen2.5-0.5B-Instruct");
var tokenizer = await transformers.LoadTokenizerAsync("Qwen/Qwen2.5-0.5B-Instruct");
// Call methods on Python objects
var text = tokenizer.CallWithKwargs<string>(
"apply_chat_template",
new object[] { messages },
new Dictionary<string, object?>
{
["tokenize"] = false,
["add_generation_prompt"] = true
}
);
// Get attributes
using var device = model.GetAttrPy("device");
// Move tensors between devices
using var inputsOnDevice = modelInputs.To(device);
// Clean up when done
model.Dispose();
tokenizer.Dispose();
PyObjectHandle Extension Methods
| Method | Description |
|---|---|
Call<T>(method, args...) |
Call a method and convert result to T |
CallPy(method, args...) |
Call a method and return PyObjectHandle |
CallWithKwargs<T>(method, args, kwargs) |
Call with keyword arguments |
Invoke(args, kwargs) |
Call the object itself (e.g., tokenizer(...)) |
GetAttr<T>(name) |
Get an attribute as T |
GetAttrPy(name) |
Get an attribute as PyObjectHandle |
To(device) |
Move tensor to device |
โ๏ธ Configuration
Environment Variables
| Variable | Description |
|---|---|
PYTHONNET_PYDLL |
Path to Python shared library (auto-detected if not set) |
PYSHARP_PYTHON_PATH |
Additional Python module search path |
Manual Initialization
PythonEngineInitializer.Initialize(
pythonHome: "/usr/local/python", // Optional: PYTHONHOME override
extraPaths: new[] { "./python", "./lib" } // Additional sys.path entries
);
๐ Project Structure
PySharp/
โโโ PySharp/ # Core library
โ โโโ Attributes/ # [PyClass], [PyModule], [PyMethod], etc.
โ โโโ Core/ # Engine, proxy, converters
โ โโโ Examples/ # Sample interfaces
โโโ PySharp.Examples.LLM/ # HuggingFace Transformers example
โโโ python/ # Python modules
โโโ PySharp.sln
๐ง How It Works
- Interface Analysis โ PySharp reads your interface attributes at runtime
- DispatchProxy โ Creates a dynamic proxy implementing your interface
- GIL Management โ Automatically acquires Python's Global Interpreter Lock
- Type Conversion โ Marshals arguments and return values between C# and Python
- Module Caching โ Python modules are cached for performance
๐งช Running Examples
Basic Math Example
cd PySharp
dotnet run
Output:
3 + 5 = 8
2 * 4 = 8
6 * 7 (async) = 42
LLM Example
cd PySharp.Examples.LLM
pip install transformers torch
dotnet run
๐ Supported Types
| C# Type | Python Type |
|---|---|
int, long |
int |
float, double |
float |
string |
str |
bool |
bool |
List<T> |
list |
Dictionary<K,V> |
dict |
PyObjectHandle |
Any Python object |
Task<T> |
Async wrapper |
๐ License
MIT License โ Use it freely in your projects.
๐ค Contributing
Contributions welcome! Please open an issue or PR.
<p align="center"> <b>PySharp</b> โ Because Python and C# should be friends. ๐๐คโก </p>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- pythonnet (>= 3.0.4)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.