pythonnet

Seamless interop between Python and the .NET Common Language Runtime — call .NET assemblies from Python or embed Python inside .NET apps.

Library
PyPI
v3.1.0
5,514stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
68/100Good
Development Activity52
Maintenance32
Community88
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture74
Code Quality75
Innovation68
Learning Curve90

Python.NET (imported as clr, published to PyPI as pythonnet) gives Python code nearly transparent access to the .NET Common Language Runtime. Once loaded, .NET namespaces behave like ordinary Python packages — from System import String or from System.Collections import * work exactly as if those types were written in Python — so existing .NET/C# assemblies and Windows-only APIs can be called from Python scripts, notebooks, and data pipelines without a rewrite. The reverse direction is supported too: .NET applications can embed a full CPython interpreter via PythonEngine.Initialize() and Py.GIL(), letting C#/.NET developers script or extend their application with Python.

Under the hood it is a hybrid project: a thin pure-Python loader (pythonnet/__init__.py, clr.py) delegates runtime bootstrapping to the clr_loader dependency, which can select Mono, .NET Framework, or CoreCLR at runtime, while the actual bridge is a large C# assembly (Python.Runtime) that talks to the CPython C API directly through unsafe native interop. It has been maintained since 2006, is supported by the .NET Foundation, and its CI matrix builds and tests across Windows/Linux/macOS on x86/x64/arm64 against Python 3.11 through 3.15.

What You Get

  • Direct import of .NET namespaces and types as Python packages via import clr; from System import String
  • Runtime selection across Mono, .NET Framework, and CoreCLR at load time through the clr_loader dependency (pythonnet.load("coreclr"), etc.)
  • An embedding API (PythonEngine.Initialize(), Py.GIL(), Py.Import()) for hosting and calling into a live Python interpreter from C#/.NET code
  • A codec/converter system (Codecs/, Converter.cs, CollectionWrappers/) that marshals primitives, collections, and custom types bidirectionally between CLR and Python object models
  • Context-manager integration so .NET IDisposable types can be used directly in Python with blocks

Common Use Cases

  • Calling existing enterprise .NET/C# libraries from Python data-science or automation scripts without reimplementing them
  • Embedding a Python scripting console or plugin system inside a WinForms/WPF/.NET desktop application
  • Combining Python’s package ecosystem with Windows-only .NET APIs (WMI, Win32 interop) in one automation script
  • Driving CLR test fixtures from pytest suites for cross-language CI coverage, as done in the project’s own tests/domain_tests

Under The Hood

Architecture The pure-Python surface (pythonnet/__init__.py, the legacy clr.py shim) is intentionally thin: it just resolves and loads a clr_loader.Runtime (Mono/.NET Framework/CoreCLR) and hands off to a large C# assembly, Python.Runtime, under src/runtime/. That assembly is where the real bridge lives — Runtime.cs wraps the low-level CPython C API (all calls require holding the GIL, as its own doc comment states), PythonEngine.cs exposes the public embedding surface (Initialize, Py.GIL(), Py.Import), TypeManager.cs/ClassManager.cs generate proxy CLR types visible to Python, and Native/ holds Python-version-specific ABI offset tables (TypeOffset311.csTypeOffset315.cs) that the bridge depends on staying in sync with each CPython release. Conversion is factored out into Codecs/ (pluggable encoder/decoder groups) and CollectionWrappers/ (list/sequence/iterable adapters), keeping marshaling logic separate from the core interop plumbing. Bridging two independent runtimes’ memory and object models is an inherently tangled problem, but the separation between native ABI code, the object/type system, and the conversion layer is coherent and traceable.

Tech Stack The interop core is C# targeting .NET Framework, Mono, and CoreCLR (CI currently builds against the .NET 10 SDK), consumed from Python 3.11–3.15. The only pure-Python runtime dependency is clr_loader (pinned >=0.3.1,<0.4.0), which performs the actual native runtime discovery and loading. The build is a custom setuptools-based pipeline (setup.py defines a build_dotnet command that shells out to dotnet build), with uv-managed dependency groups for dev (pytest, numpy, find_libpython) and docs (Sphinx, Furo theme, Breathe, sphinx-csharp). CI runs a full build-and-test matrix across Windows/Linux/macOS on x86, x64, and arm64.

Code Quality The test suite spans 40 Python test files under tests/ (pytest-based, xfail_strict enabled), backed by a companion C# test assembly (Python.Test, driven from tests/domain_tests) so behavior is verified from both the Python and CLR sides of the bridge — plus dedicated leaktest.py/stresstest.py scripts for reference-leak and stress scenarios, and a separate embed_tests/ suite in C# for the embedding direction. CI exercises this matrix across every supported OS/architecture/Python-version combination on every push and PR, which is a meaningfully high bar for a native-interop project.

API Design The project’s core idea — that import clr; from System import String just works, and that .NET IDisposable objects can be used in a Python with block — is a genuinely low-friction way to cross a language/runtime boundary that normally requires FFI boilerplate. The embedding direction is less frictionless: initializing the runtime requires explicitly setting Runtime.PythonDLL/PYTHONNET_PYDLL or hitting a BadPythonDllException, and all embedded calls must be wrapped in Py.GIL() blocks, which is necessary given the GIL but adds ceremony most callers don’t expect on first use.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search