diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 60c94dbeb..521a6cfdc 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -6,7 +6,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@v7
- name: Set up Python
uses: astral-sh/setup-uv@v7
with:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 7b1bee82c..bae02377f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -36,31 +36,14 @@ jobs:
instance: ubuntu-22.04-arm
suffix: ""
- - category: macos
- platform: x64
- instance: macos-15
- suffix: -macos-x86_64-none
-
- category: macos
platform: arm64
instance: macos-15
- suffix: -macos-aarch64-none
+ suffix: ""
- python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
+ python: ["3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"]
exclude:
- # Fails with initfs_encoding error
- - os:
- category: windows
- platform: x86
- python: "3.10"
-
- # Fails to find pytest
- - os:
- category: windows
- platform: x64
- python: '3.10'
-
# fails to call mono methods
- os:
category: windows
@@ -71,7 +54,7 @@ jobs:
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
steps:
- name: Checkout code
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
# Use main until support for architecture lands
- name: Setup .NET
diff --git a/.github/workflows/nuget-preview.yml b/.github/workflows/nuget-preview.yml
index 6de97d50e..ec39c8d8a 100644
--- a/.github/workflows/nuget-preview.yml
+++ b/.github/workflows/nuget-preview.yml
@@ -10,7 +10,7 @@ jobs:
name: Release Preview
runs-on: ubuntu-latest
environment: NuGet
- timeout-minutes: 10
+ timeout-minutes: 30
env:
PYTHONNET_SHUTDOWN_MODE: Normal
@@ -21,30 +21,25 @@ jobs:
echo "DATE_VER=$(date "+%Y-%m-%d")" >> $GITHUB_ENV
- name: Checkout code
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Setup .NET
- uses: actions/setup-dotnet@v5
+ uses: actions/setup-dotnet@v6
with:
- dotnet-version: '6.0.x'
+ dotnet-version: '10.0.x'
- - name: Set up Python 3.8
- uses: actions/setup-python@v6
+ - name: Set up Python 3.11
+ uses: astral-sh/setup-uv@v7
with:
- python-version: 3.8
- architecture: x64
+ python-version: cpython-3.11
+ cache-python: true
+ activate-environment: true
+ enable-cache: true
- name: Install dependencies
- run: |
- pip install --upgrade -r requirements.txt
- pip install numpy # for tests
-
- - name: Build and Install
- run: |
- pip install -v .
+ run: uv sync --managed-python
- - name: Set Python DLL path (non Windows)
- if: ${{ matrix.os != 'windows' }}
+ - name: Set Python DLL path
run: |
echo PYTHONNET_PYDLL=$(python -m find_libpython) >> $GITHUB_ENV
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 546413849..737472caa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,32 @@ project adheres to [Semantic Versioning][].
This document follows the conventions laid out in [Keep a CHANGELOG][].
+## 3.2.0 - 2026-09-29
+
+### Added
+
+- Support for Python 3.15 (#2729)
+- Support for free-threaded Python 3.14 (`Py_GIL_DISABLED`) (#2721)
+- Threading documentation covering GIL ownership, managed threads, and
+ free-threaded Python (#2721)
+
+### Changed
+
+- Raise the minimum supported Python version from 3.10 to 3.11 (#2729)
+- Make runtime caches and CLR type binding safe for concurrent access (#2721)
+- Migrate the Visual Studio solution to the `.slnx` format (#2733)
+- Update GitHub Actions dependencies (#2739)
+
+### Fixed
+
+- Fix races in finalization, buffer disposal, assembly path updates, and
+ Python subclass creation (#2721)
+- Fix method binding initialization when methods are first accessed (#2721)
+- Fix wheel and NuGet preview package builds
+- Python exception raised on conversion failure (#2741)
+- Introduce additional pre-checks in `PyBuffer_GetPointer` to prevent memory
+ corruption (#2745)
+
## 3.1.0 - 2026-05-23
### Added
diff --git a/MANIFEST.in b/MANIFEST.in
index 1d4889e25..3a6c29860 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,5 +4,5 @@ prune src/runtime/bin
graft src/compat
include src/pythonnet.snk
include Directory.Build.*
-include pythonnet.sln
+include pythonnet.slnx
include version.txt
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 161f4483e..d906f363e 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -23,8 +23,9 @@ speeds for Python code. If you are interested in a pure managed-code
implementation of the Python language, you should check out the
`IronPython`_ project.
-Python.NET is currently compatible and tested with Python releases from 3.7
-onwards.
+Python.NET is currently compatible and tested with Python releases 3.11
+through 3.15. Free-threaded CPython is supported starting with Python 3.14;
+see :doc:`threading` for the threading and GIL guidance.
Current releases are available on `PyPi `_
and `Nuget.org `_.
@@ -45,6 +46,7 @@ page. Use the `Python.NET issue tracker`_ to report issues.
python
dotnet
codecs
+ threading
pyreference
reference
diff --git a/doc/source/python.rst b/doc/source/python.rst
index d39081eba..2fb01ad92 100644
--- a/doc/source/python.rst
+++ b/doc/source/python.rst
@@ -481,7 +481,7 @@ Python idioms:
name = item.GetName()
Using Context Managers (IDisposable)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.NET types that implement ``IDisposable`` can be used with Python's context manager
protocol using the standard ``with`` statement. This automatically calls the object's
diff --git a/doc/source/threading.rst b/doc/source/threading.rst
new file mode 100644
index 000000000..02f7bc91a
--- /dev/null
+++ b/doc/source/threading.rst
@@ -0,0 +1,217 @@
+Threading
+=========
+
+This page explains how Python.NET interacts with the Python Global Interpreter
+Lock (GIL) and with managed threads, and what guarantees the runtime makes
+when your code is multi-threaded. It covers classic CPython builds for Python
+3.11 through 3.15 and the free-threaded builds introduced in CPython 3.13
+(``Py_GIL_DISABLED``). Python.NET supports free-threaded CPython starting with
+Python 3.14.
+
+The model in one paragraph
+--------------------------
+
+Python.NET embeds CPython, so every interaction with a Python object —
+including reading a ``PyObject``'s attributes, calling a Python callable,
+constructing a Python value, or letting a ``PyObject`` go out of scope — must
+happen while the calling thread is *attached* to the interpreter. On a
+classic (GIL-enabled) CPython build "attached" means "holds the GIL"; on a
+free-threaded build it means "has an active thread state". In both cases the
+attachment API is the same: ``Py.GIL()`` on the C# side and
+``threading.Thread`` / ``_thread`` on the Python side. Forgetting to attach
+will crash the process or corrupt memory.
+
+Acquiring the GIL from C#
+-------------------------
+
+When .NET code calls into Python it must hold the GIL. Use the ``Py.GIL()``
+disposable to acquire and release it::
+
+ using (Py.GIL())
+ {
+ dynamic np = Py.Import("numpy");
+ var arr = np.array(new[] { 1, 2, 3 });
+ // ... interact with arr ...
+ }
+
+``Py.GIL()`` is re-entrant: nesting calls on the same thread is harmless and
+cheap. Always pair acquisition with disposal — the ``using`` form does this
+automatically, and you must release the GIL on the same thread that acquired
+it.
+
+If you need a Python object to outlive the ``using`` block, copy what you
+need (e.g. ``.As()`` or ``new PyObject(value)``) before releasing the
+GIL.
+
+Releasing the GIL for long-running .NET work
+--------------------------------------------
+
+If a managed call holds the GIL but then does long-running work that does not
+touch Python (heavy CPU, blocking I/O, native interop), release the GIL so
+other Python threads can run::
+
+ IntPtr threadState = PythonEngine.BeginAllowThreads();
+ try
+ {
+ DoCpuHeavyWork(); // safe: no Python C API calls
+ }
+ finally
+ {
+ PythonEngine.EndAllowThreads(threadState);
+ }
+
+Inside the ``BeginAllowThreads``/``EndAllowThreads`` block you must not touch
+any Python object. If you need to talk to Python from worker threads spawned
+in this region, those threads must acquire the GIL themselves with
+``Py.GIL()``.
+
+Calling .NET from Python threads
+--------------------------------
+
+Calling a managed method from a Python ``threading.Thread`` works
+transparently — Python.NET handles GIL acquisition/release around the
+managed call. The managed code sees the GIL held on entry and is free to
+release it via ``BeginAllowThreads`` if it does its own blocking work.
+
+Calling Python from CLR threads
+-------------------------------
+
+A CLR thread that was *not* spawned by Python (a thread-pool task, a
+``Thread`` started in C#, an ``async`` continuation that resumed on a
+different thread, etc.) must acquire the GIL before touching any
+``PyObject``::
+
+ Task.Run(() =>
+ {
+ using (Py.GIL())
+ {
+ // safe to use PyObjects here
+ }
+ });
+
+Forgetting this is the most common pythonnet threading bug. Symptoms range
+from immediate segfaults to subtle refcount corruption that crashes much
+later.
+
+Reference counting and finalizers
+---------------------------------
+
+``PyObject`` follows the .NET ``IDisposable`` pattern. ``Dispose()`` (or the
+end of a ``using`` block) drops the underlying Python reference; the GC
+finalizer queues the same release for the next time Python.NET is on the GIL.
+
+Two practical consequences:
+
+* **Don't share a single ``PyObject`` instance across threads without
+ serialising access.** ``PyObject`` is not internally locked. If multiple
+ threads concurrently dispose the same instance, the underlying refcount can
+ go negative.
+
+* **Don't rely on the GC finalizer running promptly.** The PyObject is only
+ freed when a Python.NET API later reacquires the GIL. If your application
+ shuts down without that happening, finalizable PyObjects can be reported as
+ leaked.
+
+Free-threaded Python (PEP 703)
+------------------------------
+
+Starting with the free-threaded CPython 3.13+ build (``Py_GIL_DISABLED``),
+the GIL is no longer the serialisation point for Python C API calls.
+Python.NET is tested against the ``3.14t`` (free-threaded) interpreter and
+behaves as follows under that build:
+
+* ``Py.GIL()`` still acquires a thread state. It is functionally a no-op
+ for mutual exclusion but is still required for thread-state attachment.
+ Existing code that uses ``using (Py.GIL())`` continues to work without
+ changes.
+* ``PythonEngine.BeginAllowThreads`` / ``EndAllowThreads`` similarly
+ manage the thread state and are still needed if you want the GC and
+ other Python threads to run while you're in long-running unmanaged code.
+* Internal Python.NET caches (the reflection cache, generic-type binding
+ cache, dynamic-dispatch cache, module attribute cache, the interned-
+ string table, etc.) are thread-safe. You may read and call CLR types
+ concurrently from any number of threads without external locking.
+* The reference-counting protocol uses CPython's ``Py_REFCNT`` symbol on
+ 3.14+, which returns the merged biased + shared refcount; values you read
+ from ``PyObject.Refcount`` are correct under free-threading.
+
+Behaviour that is *unchanged* between GIL and free-threaded builds:
+
+* A managed object exposed to Python (e.g. via ``System.Object`` or a
+ Python subclass of a CLR type) is still owned by a single CLR side: you
+ must not mutate its plain CLR fields from multiple threads without your
+ own locking. Python.NET only protects its own bookkeeping, not your
+ domain data.
+* Operations on a single ``PyObject`` instance still require external
+ serialisation — see "Reference counting" above.
+
+Patterns
+--------
+
+Concurrent CLR access from Python
+"""""""""""""""""""""""""""""""""
+
+Hammering CLR attributes / generic types from many threads is supported::
+
+ from threading import Thread
+ import System
+ from System.Collections.Generic import List
+
+ def worker():
+ for _ in range(1000):
+ _ = System.String.Empty
+ _ = List[int]()
+
+ threads = [Thread(target=worker) for _ in range(8)]
+ for t in threads: t.start()
+ for t in threads: t.join()
+
+This works on both GIL and free-threaded builds.
+
+Python callback invoked from a managed thread
+"""""""""""""""""""""""""""""""""""""""""""""
+
+If a managed component calls back into a Python delegate from a thread it
+spawned, that callback path acquires the GIL internally — you do not need to
+add ``Py.GIL()`` around the Python code in the delegate.
+
+Spawning a managed thread from inside ``Py.GIL()``
+""""""""""""""""""""""""""""""""""""""""""""""""""
+
+If you start a managed thread while holding the GIL and the thread needs to
+call back into Python, release the GIL first so the new thread can acquire
+it::
+
+ IntPtr threadState;
+ using (Py.GIL())
+ {
+ var pyCallback = scope.Get("on_done");
+ threadState = PythonEngine.BeginAllowThreads(); // let workers acquire the GIL
+ try
+ {
+ // spawn workers, wait for them...
+ }
+ finally
+ {
+ PythonEngine.EndAllowThreads(threadState);
+ }
+ }
+
+Without the ``BeginAllowThreads`` the spawned thread blocks forever waiting
+for the GIL the parent thread is still holding.
+
+Common pitfalls
+---------------
+
+* Holding ``Py.GIL()`` across ``Task.Run`` / ``await`` boundaries. Async
+ continuations can resume on a different thread; the GIL handle is
+ thread-bound and must be released on the same thread that acquired it.
+* Passing a ``PyObject`` to a managed worker without taking ownership. If
+ the producer disposes its handle while the consumer is still using it,
+ the worker will operate on a freed object. Wrap the producer's
+ ``PyObject`` with ``new PyObject(value)`` before handing it off, or use
+ ``NewReference()``.
+* Calling a Python callable that does CPU-bound work without releasing the
+ GIL. Other Python threads cannot make progress in that case, even on a
+ free-threaded build where the GIL is otherwise a no-op (the callable
+ itself may still touch contended Python state).
diff --git a/pyproject.toml b/pyproject.toml
index 0966038cd..8bb80460d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,18 +13,18 @@ dependencies = [
"clr_loader>=0.3.1,<0.4.0"
]
-requires-python = ">=3.10, <3.15"
+requires-python = ">=3.11, <3.16"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Programming Language :: C#",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS :: MacOS X",
@@ -36,8 +36,7 @@ dynamic = ["version"]
dev = [
"pytest >= 6",
"find_libpython >= 0.3",
- "numpy >=2 ; python_version >= '3.10'",
- "numpy <2 ; python_version < '3.10'",
+ "numpy >=2",
]
doc = [
"sphinx",
diff --git a/pythonnet.sln b/pythonnet.sln
deleted file mode 100644
index 9dfeb44b1..000000000
--- a/pythonnet.sln
+++ /dev/null
@@ -1,194 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31912.275
-MinimumVisualStudioVersion = 15.0.26124.0
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.EmbeddingTest", "src\embed_tests\Python.EmbeddingTest.csproj", "{819E089B-4770-400E-93C6-4F7A35F0EA12}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.Test", "src\testing\Python.Test.csproj", "{14EF9518-5BB7-4F83-8686-015BD2CC788E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.DomainReloadTests", "tests\domain_tests\Python.DomainReloadTests.csproj", "{F2FB6DA3-318E-4F30-9A1F-932C667E38C5}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repo", "Repo", "{441A0123-F4C6-4EE4-9AEE-315FD79BE2D5}"
- ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- .gitignore = .gitignore
- CHANGELOG.md = CHANGELOG.md
- LICENSE = LICENSE
- README.rst = README.rst
- version.txt = version.txt
- shell.nix = shell.nix
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{D301657F-5EAF-4534-B280-B858D651B2E5}"
- ProjectSection(SolutionItems) = preProject
- .github\workflows\ARM.yml = .github\workflows\ARM.yml
- .github\workflows\main.yml = .github\workflows\main.yml
- .github\workflows\nuget-preview.yml = .github\workflows\nuget-preview.yml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57F5D701-F265-4736-A5A2-07249E7A4DA3}"
- ProjectSection(SolutionItems) = preProject
- setup.py = setup.py
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{BC426F42-8494-4AA5-82C9-5109ACD97BD1}"
- ProjectSection(SolutionItems) = preProject
- tools\geninterop\geninterop.py = tools\geninterop\geninterop.py
- EndProjectSection
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.PythonTestsRunner", "src\python_tests_runner\Python.PythonTestsRunner.csproj", "{35CBBDEB-FC07-4D04-9D3E-F88FC180110B}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{142A6752-C2C2-4F95-B982-193418001B65}"
- ProjectSection(SolutionItems) = preProject
- Directory.Build.props = Directory.Build.props
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- TraceAlloc|Any CPU = TraceAlloc|Any CPU
- TraceAlloc|x64 = TraceAlloc|x64
- TraceAlloc|x86 = TraceAlloc|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Debug|x64.Build.0 = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Debug|x86.Build.0 = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Release|Any CPU.Build.0 = Release|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Release|x64.ActiveCfg = Release|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Release|x64.Build.0 = Release|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Release|x86.ActiveCfg = Release|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.Release|x86.Build.0 = Release|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.TraceAlloc|Any CPU.ActiveCfg = TraceAlloc|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.TraceAlloc|Any CPU.Build.0 = TraceAlloc|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.TraceAlloc|x64.ActiveCfg = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.TraceAlloc|x64.Build.0 = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.TraceAlloc|x86.ActiveCfg = Debug|Any CPU
- {4E8C8FE2-0FB8-4517-B2D9-5FB2D5FC849B}.TraceAlloc|x86.Build.0 = Debug|Any CPU
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Debug|Any CPU.ActiveCfg = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Debug|Any CPU.Build.0 = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Debug|x64.ActiveCfg = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Debug|x64.Build.0 = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Debug|x86.ActiveCfg = Debug|x86
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Debug|x86.Build.0 = Debug|x86
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Release|Any CPU.ActiveCfg = Release|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Release|Any CPU.Build.0 = Release|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Release|x64.ActiveCfg = Release|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Release|x64.Build.0 = Release|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Release|x86.ActiveCfg = Release|x86
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.Release|x86.Build.0 = Release|x86
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.TraceAlloc|Any CPU.ActiveCfg = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.TraceAlloc|Any CPU.Build.0 = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.TraceAlloc|x64.ActiveCfg = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.TraceAlloc|x64.Build.0 = Debug|x64
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.TraceAlloc|x86.ActiveCfg = Debug|x86
- {E6B01706-00BA-4144-9029-186AC42FBE9A}.TraceAlloc|x86.Build.0 = Debug|x86
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Debug|x64.ActiveCfg = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Debug|x64.Build.0 = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Debug|x86.ActiveCfg = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Debug|x86.Build.0 = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Release|Any CPU.Build.0 = Release|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Release|x64.ActiveCfg = Release|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Release|x64.Build.0 = Release|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Release|x86.ActiveCfg = Release|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.Release|x86.Build.0 = Release|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.TraceAlloc|Any CPU.ActiveCfg = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.TraceAlloc|Any CPU.Build.0 = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.TraceAlloc|x64.ActiveCfg = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.TraceAlloc|x64.Build.0 = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.TraceAlloc|x86.ActiveCfg = Debug|Any CPU
- {819E089B-4770-400E-93C6-4F7A35F0EA12}.TraceAlloc|x86.Build.0 = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Debug|x64.ActiveCfg = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Debug|x64.Build.0 = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Debug|x86.Build.0 = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Release|Any CPU.Build.0 = Release|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Release|x64.ActiveCfg = Release|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Release|x64.Build.0 = Release|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Release|x86.ActiveCfg = Release|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.Release|x86.Build.0 = Release|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.TraceAlloc|Any CPU.ActiveCfg = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.TraceAlloc|Any CPU.Build.0 = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.TraceAlloc|x64.ActiveCfg = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.TraceAlloc|x64.Build.0 = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.TraceAlloc|x86.ActiveCfg = Debug|Any CPU
- {14EF9518-5BB7-4F83-8686-015BD2CC788E}.TraceAlloc|x86.Build.0 = Debug|Any CPU
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Debug|Any CPU.ActiveCfg = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Debug|Any CPU.Build.0 = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Debug|x64.ActiveCfg = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Debug|x64.Build.0 = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Debug|x86.ActiveCfg = Debug|x86
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Debug|x86.Build.0 = Debug|x86
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Release|Any CPU.ActiveCfg = Release|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Release|Any CPU.Build.0 = Release|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Release|x64.ActiveCfg = Release|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Release|x64.Build.0 = Release|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Release|x86.ActiveCfg = Release|x86
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.Release|x86.Build.0 = Release|x86
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.TraceAlloc|Any CPU.ActiveCfg = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.TraceAlloc|Any CPU.Build.0 = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.TraceAlloc|x64.ActiveCfg = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.TraceAlloc|x64.Build.0 = Debug|x64
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.TraceAlloc|x86.ActiveCfg = Debug|x86
- {4F2EA4A1-7ECA-48B5-8077-7A3C366F9931}.TraceAlloc|x86.Build.0 = Debug|x86
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Debug|x64.Build.0 = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Debug|x86.Build.0 = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Release|Any CPU.Build.0 = Release|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Release|x64.ActiveCfg = Release|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Release|x64.Build.0 = Release|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Release|x86.ActiveCfg = Release|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.Release|x86.Build.0 = Release|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.TraceAlloc|Any CPU.ActiveCfg = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.TraceAlloc|Any CPU.Build.0 = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.TraceAlloc|x64.ActiveCfg = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.TraceAlloc|x64.Build.0 = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.TraceAlloc|x86.ActiveCfg = Debug|Any CPU
- {F2FB6DA3-318E-4F30-9A1F-932C667E38C5}.TraceAlloc|x86.Build.0 = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Debug|x64.Build.0 = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Debug|x86.Build.0 = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|Any CPU.Build.0 = Release|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x64.ActiveCfg = Release|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x64.Build.0 = Release|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x86.ActiveCfg = Release|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.Release|x86.Build.0 = Release|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.TraceAlloc|Any CPU.ActiveCfg = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.TraceAlloc|Any CPU.Build.0 = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.TraceAlloc|x64.ActiveCfg = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.TraceAlloc|x64.Build.0 = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.TraceAlloc|x86.ActiveCfg = Debug|Any CPU
- {35CBBDEB-FC07-4D04-9D3E-F88FC180110B}.TraceAlloc|x86.Build.0 = Debug|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {C8845072-C642-4858-8627-27E862AD21BB}
- EndGlobalSection
-EndGlobal
diff --git a/pythonnet.slnx b/pythonnet.slnx
new file mode 100644
index 000000000..0434ecd6d
--- /dev/null
+++ b/pythonnet.slnx
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/embed_tests/Codecs.cs b/src/embed_tests/Codecs.cs
index 6159060b3..f9ea2e14f 100644
--- a/src/embed_tests/Codecs.cs
+++ b/src/embed_tests/Codecs.cs
@@ -25,15 +25,13 @@ static void TupleConversionsGeneric()
TupleCodec.Register();
var tuple = Activator.CreateInstance(typeof(T), 42, "42", new object());
T restored = default;
- using (var scope = Py.CreateScope())
- {
- void Accept(T value) => restored = value;
- using var accept = new Action(Accept).ToPython();
- scope.Set(nameof(tuple), tuple);
- scope.Set(nameof(accept), accept);
- scope.Exec($"{nameof(accept)}({nameof(tuple)})");
- Assert.That(actual: restored, Is.EqualTo(expected: tuple));
- }
+ using var scope = Py.CreateScope();
+ void Accept(T value) => restored = value;
+ using var accept = new Action(Accept).ToPython();
+ scope.Set(nameof(tuple), tuple);
+ scope.Set(nameof(accept), accept);
+ scope.Exec($"{nameof(accept)}({nameof(tuple)})");
+ Assert.That(actual: restored, Is.EqualTo(expected: tuple));
}
[Test]
@@ -46,15 +44,13 @@ static void TupleConversionsObject()
TupleCodec.Register();
var tuple = Activator.CreateInstance(typeof(T), 42.0, "42", new object());
T restored = default;
- using (var scope = Py.CreateScope())
- {
- void Accept(object value) => restored = (T)value;
- using var accept = new Action