Skip to content

Commit 51d229f

Browse files
yagwebvmuriart
authored andcommitted
Add function of passing an arbitrary .NET object as the value of an
attribute of PyObject by dynamic type
1 parent 94c266e commit 51d229f

File tree

5 files changed

+144
-15
lines changed

5 files changed

+144
-15
lines changed

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
- Sean Freitag ([@cowboygneox](https://github.com/cowboygneox))
3030
- Serge Weinstock ([@sweinst](https://github.com/sweinst))
3131
- Virgil Dupras ([@hsoft](https://github.com/hsoft))
32+
- Wenguang Yang ([@yagweb](https://github.com/yagweb))
3233
- Xavier Dupré ([@sdpython](https://github.com/sdpython))
3334
- Zane Purvis ([@zanedp](https://github.com/zanedp))
3435
- ([@ArvidJB](https://github.com/ArvidJB))

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1515
- Added Embedded tests on Appveyor (#353)
1616
- Added PY3 settings to configuration-manager (#346)
1717
- Added `Slack` chat (#384)(#383)(#386)
18+
- Added function of passing an arbitrary .NET object as the value
19+
of an attribute of PyObject (#370)(#373)
1820

1921
### Changed
2022

src/embed_tests/Python.EmbeddingTest.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
<DebugType>pdbonly</DebugType>
6666
</PropertyGroup>
6767
<ItemGroup>
68+
<Reference Include="Microsoft.CSharp" />
6869
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
6970
<HintPath>..\..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
7071
</Reference>
@@ -76,6 +77,7 @@
7677
</ItemGroup>
7778
<ItemGroup>
7879
<Compile Include="pyinitialize.cs" />
80+
<Compile Include="dynamic.cs" />
7981
<Compile Include="pyimport.cs" />
8082
<Compile Include="pyiter.cs" />
8183
<Compile Include="pylong.cs" />

src/embed_tests/dynamic.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.Text;
3+
using NUnit.Framework;
4+
using Python.Runtime;
5+
6+
namespace Python.EmbeddingTest
7+
{
8+
[TestFixture]
9+
public class dynamicTest
10+
{
11+
private Py.GILState gil;
12+
13+
[SetUp]
14+
public void SetUp()
15+
{
16+
gil = Py.GIL();
17+
}
18+
19+
[TearDown]
20+
public void TearDown()
21+
{
22+
gil.Dispose();
23+
}
24+
25+
/// <summary>
26+
/// Set the attribute of a pyobject with a .NET object.
27+
/// </summary>
28+
[Test]
29+
public void AssignObject()
30+
{
31+
StringBuilder stream = new StringBuilder();
32+
dynamic sys = Py.Import("sys");
33+
sys.testattr = stream;
34+
// Check whether there are the same object.
35+
var _stream = sys.testattr.AsManagedObject(typeof(StringBuilder));
36+
Assert.AreEqual(_stream, stream);
37+
38+
PythonEngine.RunSimpleString(
39+
"import sys\n" +
40+
"sys.testattr.Append('Hello!')\n");
41+
Assert.AreEqual(stream.ToString(), "Hello!");
42+
}
43+
44+
/// <summary>
45+
/// Set the attribute of a pyobject to null.
46+
/// </summary>
47+
[Test]
48+
public void AssignNone()
49+
{
50+
dynamic sys = Py.Import("sys");
51+
sys.testattr = new StringBuilder();
52+
Assert.IsNotNull(sys.testattr);
53+
54+
sys.testattr = null;
55+
Assert.IsNull(sys.testattr);
56+
}
57+
58+
/// <summary>
59+
/// Check whether we can get the attr of a python object when the
60+
/// value of attr is a PyObject.
61+
/// </summary>
62+
[Test]
63+
public void AssignPyObject()
64+
{
65+
dynamic sys = Py.Import("sys");
66+
dynamic io = Py.Import("io");
67+
sys.testattr = io.StringIO();
68+
dynamic bb = sys.testattr; //Get the PyObject
69+
bb.write("Hello!");
70+
Assert.AreEqual(bb.getvalue().ToString(), "Hello!");
71+
}
72+
73+
/// <summary>
74+
/// Pass the .NET object in Python side.
75+
/// </summary>
76+
[Test]
77+
public void PassObjectInPython()
78+
{
79+
StringBuilder stream = new StringBuilder();
80+
dynamic sys = Py.Import("sys");
81+
sys.testattr1 = stream;
82+
83+
//Pass the .NET object in Python side
84+
PythonEngine.RunSimpleString(
85+
"import sys\n" +
86+
"sys.testattr2 = sys.testattr1\n"
87+
);
88+
89+
//Compare in Python
90+
PythonEngine.RunSimpleString(
91+
"import sys\n" +
92+
"sys.testattr3 = sys.testattr1 is sys.testattr2\n"
93+
);
94+
Assert.AreEqual(sys.testattr3.ToString(), "True");
95+
96+
//Compare in .NET
97+
Assert.AreEqual(sys.testattr1, sys.testattr2);
98+
}
99+
100+
/// <summary>
101+
/// Pass the PyObject in .NET side
102+
/// </summary>
103+
[Test]
104+
public void PassPyObjectInNet()
105+
{
106+
StringBuilder stream = new StringBuilder();
107+
dynamic sys = Py.Import("sys");
108+
sys.testattr1 = stream;
109+
sys.testattr2 = sys.testattr1;
110+
111+
//Compare in Python
112+
PyObject res = PythonEngine.RunString(
113+
"import sys\n" +
114+
"sys.testattr3 = sys.testattr1 is sys.testattr2\n"
115+
);
116+
Assert.AreEqual(sys.testattr3.ToString(), "True");
117+
118+
//Compare in .NET
119+
Assert.AreEqual(sys.testattr1, sys.testattr2);
120+
}
121+
}
122+
}

src/runtime/pyobject.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -887,30 +887,32 @@ public override int GetHashCode()
887887
return Runtime.PyObject_Hash(obj).ToInt32();
888888
}
889889

890-
public override bool TryGetMember(GetMemberBinder binder, out object result)
890+
891+
public long Refcount
891892
{
892-
if (this.HasAttr(binder.Name))
893-
{
894-
result = CheckNone(this.GetAttr(binder.Name));
895-
return true;
896-
}
897-
else
893+
get
898894
{
899-
return base.TryGetMember(binder, out result);
895+
return Runtime.Refcount(obj);
900896
}
901897
}
902898

899+
900+
public override bool TryGetMember(GetMemberBinder binder, out object result)
901+
{
902+
result = CheckNone(this.GetAttr(binder.Name));
903+
return true;
904+
}
905+
903906
public override bool TrySetMember(SetMemberBinder binder, object value)
904907
{
905-
if (this.HasAttr(binder.Name))
906-
{
907-
this.SetAttr(binder.Name, (PyObject)value);
908-
return true;
909-
}
910-
else
908+
IntPtr ptr = Converter.ToPython(value, value?.GetType());
909+
int r = Runtime.PyObject_SetAttrString(obj, binder.Name, ptr);
910+
if (r < 0)
911911
{
912-
return base.TrySetMember(binder, value);
912+
throw new PythonException();
913913
}
914+
Runtime.XDecref(ptr);
915+
return true;
914916
}
915917

916918
private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs)

0 commit comments

Comments
 (0)