| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d39f9f6 commit 12af794
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -31,6 +31,7 @@ | |||
| 31 | 31 | - Matthias Dittrich ([@matthid](https://github.com/matthid)) | |
| 32 | 32 | - Patrick Stewart ([@patstew](https://github.com/patstew)) | |
| 33 | 33 | - Raphael Nestler ([@rnestler](https://github.com/rnestler)) | |
| 34 | + - Rickard Holmberg ([@rickardraysearch](https://github.com/rickardraysearch)) | ||
| 34 | 35 | - Sam Winstanley ([@swinstanley](https://github.com/swinstanley)) | |
| 35 | 36 | - Sean Freitag ([@cowboygneox](https://github.com/cowboygneox)) | |
| 36 | 37 | - Serge Weinstock ([@sweinst](https://github.com/sweinst)) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,6 +21,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. | |||
| 21 | 21 | derived from a .NET class has a `__namespace__` or `__assembly__` | |
| 22 | 22 | attribute (#481) | |
| 23 | 23 | - Fixed conversion of 'float' and 'double' values (#486) | |
| 24 | + - Fixed 'clrmethod' for python 2 (#492) | ||
| 24 | 25 | ||
| 25 | 26 | ||
| 26 | 27 | ## [2.3.0][] - 2017-03-11 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,4 @@ | |||
| 1 | - using System; | ||
| 1 | + using System; | ||
| 2 | 2 | using NUnit.Framework; | |
| 3 | 3 | using Python.Runtime; | |
| 4 | 4 | ||
@@ -47,5 +47,46 @@ public static void RefCountTest() | |||
| 47 | 47 | ||
| 48 | 48 | Runtime.Runtime.Py_Finalize(); | |
| 49 | 49 | } | |
| 50 | + | ||
| 51 | + [Test] | ||
| 52 | + public static void PyCheck_Iter_PyObject_IsIterable_Test() | ||
| 53 | + { | ||
| 54 | + Runtime.Runtime.Py_Initialize(); | ||
| 55 | + | ||
| 56 | + // Tests that a python list is an iterable, but not an iterator | ||
| 57 | + var pyList = Runtime.Runtime.PyList_New(0); | ||
| 58 | + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyList)); | ||
| 59 | + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyList)); | ||
| 60 | + | ||
| 61 | + // Tests that a python list iterator is both an iterable and an iterator | ||
| 62 | + var pyListIter = Runtime.Runtime.PyObject_GetIter(pyList); | ||
| 63 | + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyListIter)); | ||
| 64 | + Assert.IsTrue(Runtime.Runtime.PyIter_Check(pyListIter)); | ||
| 65 | + | ||
| 66 | + // Tests that a python float is neither an iterable nor an iterator | ||
| 67 | + var pyFloat = Runtime.Runtime.PyFloat_FromDouble(2.73); | ||
| 68 | + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(pyFloat)); | ||
| 69 | + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyFloat)); | ||
| 70 | + | ||
| 71 | + Runtime.Runtime.Py_Finalize(); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + [Test] | ||
| 75 | + public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test() | ||
| 76 | + { | ||
| 77 | + Runtime.Runtime.Py_Initialize(); | ||
| 78 | + | ||
| 79 | + // Create an instance of threading.Lock, which is one of the very few types that does not have the | ||
| 80 | + // TypeFlags.HaveIter set in Python 2. This tests a different code path in PyObject_IsIterable and PyIter_Check. | ||
| 81 | + var threading = Runtime.Runtime.PyImport_ImportModule("threading"); | ||
| 82 | + var threadingDict = Runtime.Runtime.PyModule_GetDict(threading); | ||
| 83 | + var lockType = Runtime.Runtime.PyDict_GetItemString(threadingDict, "Lock"); | ||
| 84 | + var lockInstance = Runtime.Runtime.PyObject_CallObject(lockType, Runtime.Runtime.PyTuple_New(0)); | ||
| 85 | + | ||
| 86 | + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance)); | ||
| 87 | + Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance)); | ||
| 88 | + | ||
| 89 | + Runtime.Runtime.Py_Finalize(); | ||
| 90 | + } | ||
| 50 | 91 | } | |
| 51 | 92 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -802,7 +802,7 @@ public bool IsCallable() | |||
| 802 | 802 | /// </remarks> | |
| 803 | 803 | public bool IsIterable() | |
| 804 | 804 | { | |
| 805 | - return Runtime.PyIter_Check(obj); | ||
| 805 | + return Runtime.PyObject_IsIterable(obj); | ||
| 806 | 806 | } | |
| 807 | 807 | ||
| 808 | 808 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,4 @@ | |||
| 1 | - using System; | ||
| 1 | + using System; | ||
| 2 | 2 | using System.Runtime.InteropServices; | |
| 3 | 3 | using System.Security; | |
| 4 | 4 | using System.Text; | |
@@ -274,19 +274,17 @@ internal static void Initialize() | |||
| 274 | 274 | ||
| 275 | 275 | Error = new IntPtr(-1); | |
| 276 | 276 | ||
| 277 | - #if PYTHON3 | ||
| 278 | 277 | IntPtr dllLocal = IntPtr.Zero; | |
| 279 | 278 | if (PythonDll != "__Internal") | |
| 280 | 279 | { | |
| 281 | - NativeMethods.LoadLibrary(PythonDll); | ||
| 280 | + dllLocal = NativeMethods.LoadLibrary(PythonDll); | ||
| 282 | 281 | } | |
| 283 | 282 | _PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented"); | |
| 284 | 283 | #if !(MONO_LINUX || MONO_OSX) | |
| 285 | 284 | if (dllLocal != IntPtr.Zero) | |
| 286 | 285 | { | |
| 287 | 286 | NativeMethods.FreeLibrary(dllLocal); | |
| 288 | 287 | } | |
| 289 | - #endif | ||
| 290 | 288 | #endif | |
| 291 | 289 | ||
| 292 | 290 | // Initialize modules that depend on the runtime class. | |
@@ -349,8 +347,8 @@ internal static int AtExit() | |||
| 349 | 347 | ||
| 350 | 348 | #if PYTHON3 | |
| 351 | 349 | internal static IntPtr PyBytesType; | |
| 352 | - internal static IntPtr _PyObject_NextNotImplemented; | ||
| 353 | 350 | #endif | |
| 351 | + internal static IntPtr _PyObject_NextNotImplemented; | ||
| 354 | 352 | ||
| 355 | 353 | internal static IntPtr PyNotImplemented; | |
| 356 | 354 | internal const int Py_LT = 0; | |
@@ -780,6 +778,21 @@ internal static string PyObject_GetTypeName(IntPtr op) | |||
| 780 | 778 | return Marshal.PtrToStringAnsi(ppName); | |
| 781 | 779 | } | |
| 782 | 780 | ||
| 781 | + /// <summary> | ||
| 782 | + /// Test whether the Python object is an iterable. | ||
| 783 | + /// </summary> | ||
| 784 | + internal static bool PyObject_IsIterable(IntPtr pointer) | ||
| 785 | + { | ||
| 786 | + var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); | ||
| 787 | + #if PYTHON2 | ||
| 788 | + long tp_flags = Marshal.ReadInt64(ob_type, TypeOffset.tp_flags); | ||
| 789 | + if ((tp_flags & TypeFlags.HaveIter) == 0) | ||
| 790 | + return false; | ||
| 791 | + #endif | ||
| 792 | + IntPtr tp_iter = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iter); | ||
| 793 | + return tp_iter != IntPtr.Zero; | ||
| 794 | + } | ||
| 795 | + | ||
| 783 | 796 | [DllImport(PythonDll, CallingConvention = CallingConvention.Cdecl)] | |
| 784 | 797 | internal static extern int PyObject_HasAttrString(IntPtr pointer, string name); | |
| 785 | 798 | ||
@@ -1425,17 +1438,17 @@ internal static bool PyTuple_Check(IntPtr ob) | |||
| 1425 | 1438 | // Python iterator API | |
| 1426 | 1439 | //==================================================================== | |
| 1427 | 1440 | ||
| 1428 | - #if PYTHON2 | ||
| 1429 | - [DllImport(PythonDll, CallingConvention = CallingConvention.Cdecl)] | ||
| 1430 | - internal static extern bool PyIter_Check(IntPtr pointer); | ||
| 1431 | - #elif PYTHON3 | ||
| 1432 | 1441 | internal static bool PyIter_Check(IntPtr pointer) | |
| 1433 | 1442 | { | |
| 1434 | - var ob_type = (IntPtr)Marshal.PtrToStructure(pointer + ObjectOffset.ob_type, typeof(IntPtr)); | ||
| 1435 | - IntPtr tp_iternext = ob_type + TypeOffset.tp_iternext; | ||
| 1436 | - return tp_iternext != null && tp_iternext != _PyObject_NextNotImplemented; | ||
| 1437 | - } | ||
| 1443 | + var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); | ||
| 1444 | + #if PYTHON2 | ||
| 1445 | + long tp_flags = Marshal.ReadInt64(ob_type, TypeOffset.tp_flags); | ||
| 1446 | + if ((tp_flags & TypeFlags.HaveIter) == 0) | ||
| 1447 | + return false; | ||
| 1438 | 1448 | #endif | |
| 1449 | + IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext); | ||
| 1450 | + return tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented; | ||
| 1451 | + } | ||
| 1439 | 1452 | ||
| 1440 | 1453 | [DllImport(PythonDll, CallingConvention = CallingConvention.Cdecl)] | |
| 1441 | 1454 | internal static extern IntPtr PyIter_Next(IntPtr pointer); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,73 @@ | |||
| 1 | + # -*- coding: utf-8 -*- | ||
| 2 | + | ||
| 3 | + """Test clrmethod and clrproperty support for calling methods and getting/setting python properties from CLR.""" | ||
| 4 | + | ||
| 5 | + import Python.Test as Test | ||
| 6 | + import System | ||
| 7 | + import pytest | ||
| 8 | + import clr | ||
| 9 | + | ||
| 10 | + class ExampleClrClass(System.Object): | ||
| 11 | + __namespace__ = "PyTest" | ||
| 12 | + def __init__(self): | ||
| 13 | + self._x = 3 | ||
| 14 | + @clr.clrmethod(int, [int]) | ||
| 15 | + def test(self, x): | ||
| 16 | + return x*2 | ||
| 17 | + | ||
| 18 | + def get_X(self): | ||
| 19 | + return self._x | ||
| 20 | + def set_X(self, value): | ||
| 21 | + self._x = value | ||
| 22 | + X = clr.clrproperty(int, get_X, set_X) | ||
| 23 | + | ||
| 24 | + @clr.clrproperty(int) | ||
| 25 | + def Y(self): | ||
| 26 | + return self._x * 2 | ||
| 27 | + | ||
| 28 | + def test_set_and_get_property_from_py(): | ||
| 29 | + """Test setting and getting clr-accessible properties from python.""" | ||
| 30 | + t = ExampleClrClass() | ||
| 31 | + assert t.X == 3 | ||
| 32 | + assert t.Y == 3 * 2 | ||
| 33 | + t.X = 4 | ||
| 34 | + assert t.X == 4 | ||
| 35 | + assert t.Y == 4 * 2 | ||
| 36 | + | ||
| 37 | + def test_set_and_get_property_from_clr(): | ||
| 38 | + """Test setting and getting clr-accessible properties from the clr.""" | ||
| 39 | + t = ExampleClrClass() | ||
| 40 | + assert t.GetType().GetProperty("X").GetValue(t) == 3 | ||
| 41 | + assert t.GetType().GetProperty("Y").GetValue(t) == 3 * 2 | ||
| 42 | + t.GetType().GetProperty("X").SetValue(t, 4) | ||
| 43 | + assert t.GetType().GetProperty("X").GetValue(t) == 4 | ||
| 44 | + assert t.GetType().GetProperty("Y").GetValue(t) == 4 * 2 | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + def test_set_and_get_property_from_clr_and_py(): | ||
| 48 | + """Test setting and getting clr-accessible properties alternatingly from the clr and from python.""" | ||
| 49 | + t = ExampleClrClass() | ||
| 50 | + assert t.GetType().GetProperty("X").GetValue(t) == 3 | ||
| 51 | + assert t.GetType().GetProperty("Y").GetValue(t) == 3 * 2 | ||
| 52 | + assert t.X == 3 | ||
| 53 | + assert t.Y == 3 * 2 | ||
| 54 | + t.GetType().GetProperty("X").SetValue(t, 4) | ||
| 55 | + assert t.GetType().GetProperty("X").GetValue(t) == 4 | ||
| 56 | + assert t.GetType().GetProperty("Y").GetValue(t) == 4 * 2 | ||
| 57 | + assert t.X == 4 | ||
| 58 | + assert t.Y == 4 * 2 | ||
| 59 | + t.X = 5 | ||
| 60 | + assert t.GetType().GetProperty("X").GetValue(t) == 5 | ||
| 61 | + assert t.GetType().GetProperty("Y").GetValue(t) == 5 * 2 | ||
| 62 | + assert t.X == 5 | ||
| 63 | + assert t.Y == 5 * 2 | ||
| 64 | + | ||
| 65 | + def test_method_invocation_from_py(): | ||
| 66 | + """Test calling a clr-accessible method from python.""" | ||
| 67 | + t = ExampleClrClass() | ||
| 68 | + assert t.test(41) == 41*2 | ||
| 69 | + | ||
| 70 | + def test_method_invocation_from_clr(): | ||
| 71 | + """Test calling a clr-accessible method from the clr.""" | ||
| 72 | + t = ExampleClrClass() | ||
| 73 | + assert t.GetType().GetMethod("test").Invoke(t, [37]) == 37*2 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments