diff --git a/AUTHORS.md b/AUTHORS.md
index 2a2110f26..64511275b 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -29,6 +29,7 @@
- Sean Freitag ([@cowboygneox](https://github.com/cowboygneox))
- Serge Weinstock ([@sweinst](https://github.com/sweinst))
- Virgil Dupras ([@hsoft](https://github.com/hsoft))
+- Wenguang Yang ([@yagweb](https://github.com/yagweb))
- Xavier Dupré ([@sdpython](https://github.com/sdpython))
- Zane Purvis ([@zanedp](https://github.com/zanedp))
- ([@ArvidJB](https://github.com/ArvidJB))
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9161b3977..e55ed6245 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
- Added Embedded tests on Appveyor (#353)
- Added PY3 settings to configuration-manager (#346)
- Added `Slack` chat (#384)(#383)(#386)
+- Added function of passing an arbitrary .NET object as the value
+ of an attribute of PyObject (#370)(#373)
### Changed
diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj
index a2e92ed19..ef011d044 100644
--- a/src/embed_tests/Python.EmbeddingTest.csproj
+++ b/src/embed_tests/Python.EmbeddingTest.csproj
@@ -65,6 +65,7 @@
pdbonly
+
..\..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll
@@ -76,6 +77,7 @@
+
diff --git a/src/embed_tests/dynamic.cs b/src/embed_tests/dynamic.cs
new file mode 100644
index 000000000..c70fe203c
--- /dev/null
+++ b/src/embed_tests/dynamic.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Text;
+using NUnit.Framework;
+using Python.Runtime;
+
+namespace Python.EmbeddingTest
+{
+ [TestFixture]
+ public class dynamicTest
+ {
+ private Py.GILState gil;
+
+ [SetUp]
+ public void SetUp()
+ {
+ gil = Py.GIL();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ gil.Dispose();
+ }
+
+ ///
+ /// Set the attribute of a pyobject with a .NET object.
+ ///
+ [Test]
+ public void AssignObject()
+ {
+ StringBuilder stream = new StringBuilder();
+ dynamic sys = Py.Import("sys");
+ sys.testattr = stream;
+ // Check whether there are the same object.
+ var _stream = sys.testattr.AsManagedObject(typeof(StringBuilder));
+ Assert.AreEqual(_stream, stream);
+
+ PythonEngine.RunSimpleString(
+ "import sys\n" +
+ "sys.testattr.Append('Hello!')\n");
+ Assert.AreEqual(stream.ToString(), "Hello!");
+ }
+
+ ///
+ /// Set the attribute of a pyobject to null.
+ ///
+ [Test]
+ public void AssignNone()
+ {
+ dynamic sys = Py.Import("sys");
+ sys.testattr = new StringBuilder();
+ Assert.IsNotNull(sys.testattr);
+
+ sys.testattr = null;
+ Assert.IsNull(sys.testattr);
+ }
+
+ ///
+ /// Check whether we can get the attr of a python object when the
+ /// value of attr is a PyObject.
+ ///
+ [Test]
+ public void AssignPyObject()
+ {
+ dynamic sys = Py.Import("sys");
+ dynamic io = Py.Import("io");
+ sys.testattr = io.StringIO();
+ dynamic bb = sys.testattr; //Get the PyObject
+ bb.write("Hello!");
+ Assert.AreEqual(bb.getvalue().ToString(), "Hello!");
+ }
+
+ ///
+ /// Pass the .NET object in Python side.
+ ///
+ [Test]
+ public void PassObjectInPython()
+ {
+ StringBuilder stream = new StringBuilder();
+ dynamic sys = Py.Import("sys");
+ sys.testattr1 = stream;
+
+ //Pass the .NET object in Python side
+ PythonEngine.RunSimpleString(
+ "import sys\n" +
+ "sys.testattr2 = sys.testattr1\n"
+ );
+
+ //Compare in Python
+ PythonEngine.RunSimpleString(
+ "import sys\n" +
+ "sys.testattr3 = sys.testattr1 is sys.testattr2\n"
+ );
+ Assert.AreEqual(sys.testattr3.ToString(), "True");
+
+ //Compare in .NET
+ Assert.AreEqual(sys.testattr1, sys.testattr2);
+ }
+
+ ///
+ /// Pass the PyObject in .NET side
+ ///
+ [Test]
+ public void PassPyObjectInNet()
+ {
+ StringBuilder stream = new StringBuilder();
+ dynamic sys = Py.Import("sys");
+ sys.testattr1 = stream;
+ sys.testattr2 = sys.testattr1;
+
+ //Compare in Python
+ PyObject res = PythonEngine.RunString(
+ "import sys\n" +
+ "sys.testattr3 = sys.testattr1 is sys.testattr2\n"
+ );
+ Assert.AreEqual(sys.testattr3.ToString(), "True");
+
+ //Compare in .NET
+ Assert.AreEqual(sys.testattr1, sys.testattr2);
+ }
+ }
+}
diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs
index 3296d81f8..47f413409 100644
--- a/src/runtime/pyobject.cs
+++ b/src/runtime/pyobject.cs
@@ -887,30 +887,32 @@ public override int GetHashCode()
return Runtime.PyObject_Hash(obj).ToInt32();
}
- public override bool TryGetMember(GetMemberBinder binder, out object result)
+
+ public long Refcount
{
- if (this.HasAttr(binder.Name))
- {
- result = CheckNone(this.GetAttr(binder.Name));
- return true;
- }
- else
+ get
{
- return base.TryGetMember(binder, out result);
+ return Runtime.Refcount(obj);
}
}
+
+ public override bool TryGetMember(GetMemberBinder binder, out object result)
+ {
+ result = CheckNone(this.GetAttr(binder.Name));
+ return true;
+ }
+
public override bool TrySetMember(SetMemberBinder binder, object value)
{
- if (this.HasAttr(binder.Name))
- {
- this.SetAttr(binder.Name, (PyObject)value);
- return true;
- }
- else
+ IntPtr ptr = Converter.ToPython(value, value?.GetType());
+ int r = Runtime.PyObject_SetAttrString(obj, binder.Name, ptr);
+ if (r < 0)
{
- return base.TrySetMember(binder, value);
+ throw new PythonException();
}
+ Runtime.XDecref(ptr);
+ return true;
}
private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs)