Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
- Added `clr.GetClrType` (#432, #433)
- Allowed passing `None` for nullable args (#460)
- Added keyword arguments based on C# syntax for calling CPython methods (#461)
- Implemented GetDynamicMemberNames() for PyObject to allow dynamic object members to be visible in the debugger (#443)

### Changed

Expand Down
21 changes: 9 additions & 12 deletions src/embed_tests/Python.EmbeddingTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,45 +26,41 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'DebugMono'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants Condition="'$(DefineConstants)' == ''">DEBUG;TRACE</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS4;TRACE;DEBUG</DefineConstants>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes are not necessary, are they?

<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseMono'">
<DefineConstants Condition="'$(DefineConstants)' == ''">
</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS4</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'DebugWin'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants Condition="'$(DefineConstants)' == ''">DEBUG;TRACE</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS2;TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseWin'">
<DefineConstants Condition="'$(DefineConstants)' == ''">
</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON2;PYTHON27;UCS2</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'DebugMonoPY3'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants Condition="'$(DefineConstants)' == ''">DEBUG;TRACE</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON36;UCS4;TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseMonoPY3'">
<DefineConstants Condition="'$(DefineConstants)' == ''">
</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON36;UCS4</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'DebugWinPY3'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants Condition="'$(DefineConstants)' == ''">DEBUG;TRACE</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON36;UCS2;TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'ReleaseWinPY3'">
<DefineConstants Condition="'$(DefineConstants)' == ''">
</DefineConstants>
<DefineConstants Condition="'$(DefineConstants)' == ''">PYTHON3;PYTHON36;UCS2</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
</PropertyGroup>
Expand Down Expand Up @@ -93,6 +89,7 @@
<Compile Include="TestPyList.cs" />
<Compile Include="TestPyLong.cs" />
<Compile Include="TestPyNumber.cs" />
<Compile Include="TestPyObject.cs" />
<Compile Include="TestPySequence.cs" />
<Compile Include="TestPyString.cs" />
<Compile Include="TestPythonException.cs" />
Expand Down
104 changes: 104 additions & 0 deletions src/embed_tests/TestPyObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Python.Runtime;

namespace Python.EmbeddingTest
{
public class TestPyObject
{
[OneTimeSetUp]
public void SetUp()
{
PythonEngine.Initialize();
}

[OneTimeTearDown]
public void Dispose()
{
PythonEngine.Shutdown();
}

[Test]
public void TestGetDynamicMemberNames()
{
List<string> expectedMemberNames = new List<string>
{
"__class__",
"__delattr__",
"__dict__",
#if PYTHON3
"__dir__",
#endif
"__doc__",
#if PYTHON3
"__eq__",
#endif
"__format__",
#if PYTHON3
"__ge__",
#endif
"__getattribute__",
#if PYTHON3
"__gt__",
#endif
"__hash__",
"__init__",
#if PYTHON36
"__init_subclass__",
#endif
#if PYTHON3
"__le__",
"__lt__",
#endif
"__module__",
#if PYTHON3
"__ne__",
#endif
"__new__",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The defines here make the whole thing quite brittle, I think, to me it would be perfectly fine to just check that the explicitly added members exist (i.e. add, getNumber etc.).

"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"add",
"getNumber",
"member1",
"member2"
};

PyDict locals = new PyDict();

PythonEngine.Exec(@"
class MemberNamesTest(object):
def __init__(self):
self.member1 = 123
self.member2 = 'Test string'

def getNumber(self):
return 123

def add(self, x, y):
return x + y

a = MemberNamesTest()
", null, locals.Handle);

PyObject a = locals.GetItem("a");

IEnumerable<string> membernames = a.GetDynamicMemberNames();

Assert.AreEqual(expectedMemberNames.Count, membernames.Count(), "Unexpected number of members.");

IEnumerable<Tuple<string, string>> results = expectedMemberNames.Zip(membernames, (x, y) => new Tuple<string, string>(x, y));
foreach (Tuple<string, string> result in results)
{
Assert.AreEqual(result.Item1, result.Item2, "Unexpected member name.");
}
}
}
}
16 changes: 16 additions & 0 deletions src/runtime/pyobject.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;

Expand Down Expand Up @@ -1238,5 +1239,20 @@ public override bool TryUnaryOperation(UnaryOperationBinder binder, out object r
result = CheckNone(new PyObject(res));
return true;
}

/// <summary>
/// Returns the enumeration of all dynamic member names.
/// </summary>
/// <remarks>
/// This method exists for debugging purposes only.
/// </remarks>
/// <returns>A sequence that contains dynamic member names.</returns>
public override IEnumerable<string> GetDynamicMemberNames()
{
foreach (PyObject pyObj in Dir())
{
yield return pyObj.ToString();
}
}
}
}