diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs
index ea1181731..1fd8e04d1 100644
--- a/src/runtime/classderived.cs
+++ b/src/runtime/classderived.cs
@@ -786,7 +786,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, Objec
PyObject[] pyargs = new PyObject[args.Length];
for (int i = 0; i < args.Length; ++i)
{
- pyargs[i] = new PyObject(Converter.ToPython(args[i], args[i].GetType()));
+ pyargs[i] = new PyObject(Converter.ToPython(args[i], args[i]?.GetType()));
disposeList.Add(pyargs[i]);
}
diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs
index cdc610c2c..66ddfad5d 100644
--- a/src/runtime/converter.cs
+++ b/src/runtime/converter.cs
@@ -228,7 +228,7 @@ internal static IntPtr ToPython(Object value, Type type)
{
foreach (object o in (IEnumerable)value)
{
- using (var p = new PyObject(ToPython(o, o.GetType())))
+ using (var p = new PyObject(ToPython(o, o?.GetType())))
resultlist.Append(p);
}
Runtime.Incref(resultlist.Handle);
@@ -962,7 +962,7 @@ public static class ConverterExtension
{
public static PyObject ToPython(this object o)
{
- return new PyObject(Converter.ToPython(o, o.GetType()));
+ return new PyObject(Converter.ToPython(o, o?.GetType()));
}
}
}
\ No newline at end of file
diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs
index 738985598..c2ddf564b 100644
--- a/src/runtime/moduleobject.cs
+++ b/src/runtime/moduleobject.cs
@@ -35,7 +35,10 @@ public ModuleObject(string name) : base()
string docstring = "Namespace containing types from the following assemblies:\n\n";
foreach (Assembly a in AssemblyManager.GetAssemblies(name))
{
- filename = a.Location;
+ if (!a.IsDynamic && a.Location != null)
+ {
+ filename = a.Location;
+ }
docstring += "- " + a.FullName + "\n";
}
diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs
index 42b8d71b4..308e71ffb 100644
--- a/src/runtime/pyobject.cs
+++ b/src/runtime/pyobject.cs
@@ -939,7 +939,7 @@ public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (this.HasAttr(binder.Name))
{
- result = this.GetAttr(binder.Name);
+ result = CheckNone(this.GetAttr(binder.Name));
return true;
}
else
@@ -972,7 +972,7 @@ private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs)
}
else
{
- ptr = Converter.ToPython(inargs[i], inargs[i].GetType());
+ ptr = Converter.ToPython(inargs[i], inargs[i]?.GetType());
}
if (Runtime.PyTuple_SetItem(argtuple, i, ptr) < 0)
throw new PythonException();
@@ -999,7 +999,7 @@ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, o
try
{
GetArgs(args, out pyargs, out kwargs);
- result = InvokeMethod(binder.Name, pyargs, kwargs);
+ result = CheckNone(InvokeMethod(binder.Name, pyargs, kwargs));
}
finally
{
@@ -1023,7 +1023,7 @@ public override bool TryInvoke(InvokeBinder binder, object[] args, out object re
try
{
GetArgs(args, out pyargs, out kwargs);
- result = Invoke(pyargs, kwargs);
+ result = CheckNone(Invoke(pyargs, kwargs));
}
finally
{
@@ -1133,10 +1133,25 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, Object arg
result = null;
return false;
}
- result = new PyObject(res);
+ result = CheckNone(new PyObject(res));
return true;
}
+ // Workaround for https://bugzilla.xamarin.com/show_bug.cgi?id=41509
+ // See https://github.com/pythonnet/pythonnet/pull/219
+ private static object CheckNone(PyObject pyObj)
+ {
+ if (pyObj != null)
+ {
+ if (pyObj.obj == Runtime.PyNone)
+ {
+ return null;
+ }
+ }
+
+ return pyObj;
+ }
+
public override bool TryUnaryOperation(UnaryOperationBinder binder, out Object result)
{
int r;
@@ -1170,7 +1185,7 @@ public override bool TryUnaryOperation(UnaryOperationBinder binder, out Object r
result = null;
return false;
}
- result = new PyObject(res);
+ result = CheckNone(new PyObject(res));
return true;
}
}
diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs
index 7e37d6211..cf9bfb9ee 100644
--- a/src/runtime/pythonengine.cs
+++ b/src/runtime/pythonengine.cs
@@ -487,7 +487,7 @@ public static KeywordArguments kw(params object[] kv)
if (kv[i + 1] is PyObject)
value = ((PyObject)kv[i + 1]).Handle;
else
- value = Converter.ToPython(kv[i + 1], kv[i + 1].GetType());
+ value = Converter.ToPython(kv[i + 1], kv[i + 1]?.GetType());
if (Runtime.PyDict_SetItemString(dict.Handle, (string)kv[i], value) != 0)
throw new ArgumentException(string.Format("Cannot add key '{0}' to dictionary.", (string)kv[i]));
if (!(kv[i + 1] is PyObject))
diff --git a/src/testing/Python.Test.csproj b/src/testing/Python.Test.csproj
index 354a6eae6..56efda8e3 100644
--- a/src/testing/Python.Test.csproj
+++ b/src/testing/Python.Test.csproj
@@ -108,6 +108,7 @@
+
@@ -127,6 +128,7 @@
+
3.5
diff --git a/src/testing/callbacktest.cs b/src/testing/callbacktest.cs
new file mode 100644
index 000000000..81389289d
--- /dev/null
+++ b/src/testing/callbacktest.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Python.Test
+{
+ //========================================================================
+ // Tests callbacks into python code.
+ //========================================================================
+
+ public class CallbackTest
+ {
+ public string Call_simpleDefaultArg_WithNull(string moduleName)
+ {
+ using (Runtime.Py.GIL())
+ {
+ dynamic module = Runtime.Py.Import(moduleName);
+ return module.simpleDefaultArg(null);
+ }
+ }
+ public string Call_simpleDefaultArg_WithEmptyArgs(string moduleName)
+ {
+ using (Runtime.Py.GIL())
+ {
+ dynamic module = Runtime.Py.Import(moduleName);
+ return module.simpleDefaultArg();
+ }
+ }
+ }
+}
diff --git a/src/tests/runtests.py b/src/tests/runtests.py
index 3a7bde07b..660d3442d 100644
--- a/src/tests/runtests.py
+++ b/src/tests/runtests.py
@@ -18,6 +18,7 @@
# other test modules that import System.Windows.Forms
# run first. They must not do module level import/AddReference()
# of the System.Windows.Forms namespace.
+ 'test_suite',
'test_event',
'test_constructors',
'test_enum',
diff --git a/src/tests/test_suite/__init__.py b/src/tests/test_suite/__init__.py
new file mode 100644
index 000000000..1ca730d7b
--- /dev/null
+++ b/src/tests/test_suite/__init__.py
@@ -0,0 +1,12 @@
+import unittest
+
+__all__ = ['test_suite']
+
+from .test_import import test_suite as import_tests
+from .test_callback import test_suite as callback_tests
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTests((import_tests(),))
+ suite.addTests((callback_tests(),))
+ return suite
\ No newline at end of file
diff --git a/src/tests/test_suite/_missing_import.py b/src/tests/test_suite/_missing_import.py
new file mode 100644
index 000000000..629ff95be
--- /dev/null
+++ b/src/tests/test_suite/_missing_import.py
@@ -0,0 +1,2 @@
+
+import this_package_should_never_exist_ever
\ No newline at end of file
diff --git a/src/tests/test_suite/test_callback.py b/src/tests/test_suite/test_callback.py
new file mode 100644
index 000000000..16c45914d
--- /dev/null
+++ b/src/tests/test_suite/test_callback.py
@@ -0,0 +1,30 @@
+import unittest, sys
+import clr
+
+this_module = sys.modules[__name__]
+clr.AddReference("Python.Test")
+import Python.Test as Test
+from Python.Test import CallbackTest
+test_instance = CallbackTest()
+
+def simpleDefaultArg(arg = 'test'):
+ return arg
+
+class CallbackTests(unittest.TestCase):
+ """Test that callbacks from C# into python work."""
+
+ def testDefaultForNull(self):
+ """Test that C# can use null for an optional python argument"""
+ retVal = test_instance.Call_simpleDefaultArg_WithNull(__name__)
+ pythonRetVal = simpleDefaultArg(None)
+ self.assertEquals(retVal, pythonRetVal)
+
+ def testDefaultForNone(self):
+ """Test that C# can use no argument for an optional python argument"""
+ retVal = test_instance.Call_simpleDefaultArg_WithEmptyArgs(__name__)
+ pythonRetVal = simpleDefaultArg()
+ self.assertEquals(retVal, pythonRetVal)
+
+def test_suite():
+ return unittest.makeSuite(CallbackTests)
+
diff --git a/src/tests/test_suite/test_import.py b/src/tests/test_suite/test_import.py
new file mode 100644
index 000000000..b6d155af3
--- /dev/null
+++ b/src/tests/test_suite/test_import.py
@@ -0,0 +1,16 @@
+import unittest
+
+class ImportTests(unittest.TestCase):
+ """Test the import statement."""
+
+ def testRealtiveMissingImport(self):
+ """Test that a relative missing import doesn't crash. Some modules use this to check if a package is installed (realtive import in the site-packages folder"""
+ try:
+ from . import _missing_import
+ except ImportError:
+ pass
+
+
+def test_suite():
+ return unittest.makeSuite(ImportTests)
+