Skip to content

Commit b0d748e

Browse files
committed
adds extension object.GetRawPythonProxy()
GetRawPythonProxy creates a PyObject pointing to the specified object without performing any coversions, which lets .NET code to pass CLR objects as-is, if it needs Python to have direct access to them. This enables codecs to create arbitrary proxy objects, bypassing default conversions or other registered codecs.
1 parent 9fd877e commit b0d748e

File tree

6 files changed

+57
-0
lines changed

6 files changed

+57
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1313
- Added function that sets Py_NoSiteFlag to 1.
1414
- Added support for Jetson Nano.
1515
- Added support for __len__ for .NET classes that implement ICollection
16+
- Added `object.GetRawPythonProxy() -> PyObject` extension method, that bypasses any conversions
1617

1718
### Changed
1819

pythonnet.15.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ EndProject
1717
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repo", "Repo", "{441A0123-F4C6-4EE4-9AEE-315FD79BE2D5}"
1818
ProjectSection(SolutionItems) = preProject
1919
.editorconfig = .editorconfig
20+
.gitignore = .gitignore
21+
CHANGELOG.md = CHANGELOG.md
22+
README.rst = README.rst
2023
EndProjectSection
2124
EndProject
2225
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{D301657F-5EAF-4534-B280-B858D651B2E5}"

src/embed_tests/TestConverter.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
using System.Collections.Generic;
12
using NUnit.Framework;
23
using Python.Runtime;
34

45
namespace Python.EmbeddingTest
56
{
7+
using System;
8+
69
public class TestConverter
710
{
811
[OneTimeSetUp]
@@ -44,5 +47,26 @@ public void TestConvertDoubleToManaged(
4447
Assert.IsTrue(converted);
4548
Assert.IsTrue(((double) convertedValue).Equals(testValue));
4649
}
50+
51+
[Test]
52+
public void RawListProxy()
53+
{
54+
var list = new List<string> {"hello", "world"};
55+
var listProxy = list.GetRawPythonProxy();
56+
var clrObject = (CLRObject)ManagedType.GetManagedObject(listProxy.Handle);
57+
Assert.AreSame(list, clrObject.inst);
58+
}
59+
60+
[Test]
61+
public void RawPyObjectProxy()
62+
{
63+
var pyObject = "hello world!".ToPython();
64+
var pyObjectProxy = pyObject.GetRawPythonProxy();
65+
var clrObject = (CLRObject)ManagedType.GetManagedObject(pyObjectProxy.Handle);
66+
Assert.AreSame(pyObject, clrObject.inst);
67+
68+
var proxiedHandle = pyObjectProxy.GetAttr("Handle").As<IntPtr>();
69+
Assert.AreEqual(pyObject.Handle, proxiedHandle);
70+
}
4771
}
4872
}

src/runtime/NewReference.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ public void Dispose()
3333
this.pointer = IntPtr.Zero;
3434
}
3535

36+
/// <summary>
37+
/// Creates <see cref="NewReference"/> from a raw pointer
38+
/// </summary>
39+
public static NewReference DangerousFromPointer(IntPtr pointer)
40+
=> new NewReference {pointer = pointer};
41+
3642
[Pure]
3743
internal static IntPtr DangerousGetAddress(in NewReference reference)
3844
=> IsNull(reference) ? throw new NullReferenceException() : reference.pointer;

src/runtime/clrobject.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,17 @@ internal static IntPtr GetInstHandle(object ob)
6868
CLRObject co = GetInstance(ob);
6969
return co.pyHandle;
7070
}
71+
72+
/// <summary>
73+
/// Creates <see cref="CLRObject"/> proxy for the given object,
74+
/// and returns a <see cref="NewReference"/> to it.
75+
/// </summary>
76+
internal static NewReference MakeNewReference(object obj)
77+
{
78+
if (obj is null) throw new ArgumentNullException(nameof(obj));
79+
80+
// TODO: CLRObject currently does not have Dispose or finalizer which might change in the future
81+
return NewReference.DangerousFromPointer(GetInstHandle(obj));
82+
}
7183
}
7284
}

src/runtime/converter.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,5 +967,16 @@ public static PyObject ToPython(this object o)
967967
{
968968
return new PyObject(Converter.ToPython(o, o?.GetType()));
969969
}
970+
971+
/// <summary>
972+
/// Gets raw Python proxy for this object (bypasses all conversions,
973+
/// except <c>null</c> &lt;==&gt; <c>None</c>)
974+
/// </summary>
975+
public static PyObject GetRawPythonProxy(this object o)
976+
{
977+
if (o is null) return new PyObject(new BorrowedReference(Runtime.PyNone));
978+
979+
return CLRObject.MakeNewReference(o).MoveToPyObject();
980+
}
970981
}
971982
}

0 commit comments

Comments
 (0)