From 556882de020032df9d77ccd81ac754a55069f3ec Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Thu, 3 Nov 2022 00:29:37 +0100 Subject: [PATCH 01/12] Reset version to dev --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index cb2b00e4f..0f9d6b15d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.0.1 +3.1.0-dev From 17296982aa2e0780a09205b36d99d329c4d337f7 Mon Sep 17 00:00:00 2001 From: Rolf Madsen Date: Wed, 30 Nov 2022 22:38:42 +0100 Subject: [PATCH 02/12] 1776 Generic Virtual Method Causes Invalid Program: Fix + test (#2026) - If a method is virtual AND generic, it cannot be overridden by the python class. Hence the method call is deferred to the base class. - Added a unit test which verifies this behavior is now working. NOTE: The test causes crash when run from `PythonTestRunner`. See https://github.com/pythonnet/pythonnet/issues/2035 --- CHANGELOG.md | 2 ++ src/runtime/Types/ClassDerived.cs | 5 ++++- src/testing/generictest.cs | 8 ++++++++ tests/test_subclass.py | 14 +++++++++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13bf09c2c..2347895a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Fixed +- Fixed error occuring when inheriting a class containing a virtual generic method. + ## [3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03 ### Added diff --git a/src/runtime/Types/ClassDerived.cs b/src/runtime/Types/ClassDerived.cs index cf6d9b16b..61c602783 100644 --- a/src/runtime/Types/ClassDerived.cs +++ b/src/runtime/Types/ClassDerived.cs @@ -220,7 +220,10 @@ internal static Type CreateDerivedType(string name, foreach (MethodInfo method in methods) { if (!method.Attributes.HasFlag(MethodAttributes.Virtual) | - method.Attributes.HasFlag(MethodAttributes.Final)) + method.Attributes.HasFlag(MethodAttributes.Final) + // overriding generic virtual methods is not supported + // so a call to that should be deferred to the base class method. + || method.IsGenericMethod) { continue; } diff --git a/src/testing/generictest.cs b/src/testing/generictest.cs index 238435811..b333910c2 100644 --- a/src/testing/generictest.cs +++ b/src/testing/generictest.cs @@ -136,4 +136,12 @@ public static T[] EchoRange(T[] items) return items; } } + + public abstract class GenericVirtualMethodTest + { + public virtual Q VirtMethod(Q arg1) + { + return arg1; + } + } } diff --git a/tests/test_subclass.py b/tests/test_subclass.py index a51e89da3..504b82548 100644 --- a/tests/test_subclass.py +++ b/tests/test_subclass.py @@ -9,7 +9,7 @@ import System import pytest from Python.Test import (IInterfaceTest, SubClassTest, EventArgsTest, - FunctionsTest, IGenericInterface) + FunctionsTest, IGenericInterface, GenericVirtualMethodTest) from System.Collections.Generic import List @@ -327,3 +327,15 @@ def test_generic_interface(): obj = GenericInterfaceImpl() SpecificInterfaceUser(obj, Int32(0)) GenericInterfaceUser[Int32](obj, Int32(0)) + +def test_virtual_generic_method(): + class OverloadingSubclass(GenericVirtualMethodTest): + __namespace__ = "test_virtual_generic_method_cls" + class OverloadingSubclass2(OverloadingSubclass): + __namespace__ = "test_virtual_generic_method_cls" + obj = OverloadingSubclass() + assert obj.VirtMethod[int](5) == 5 + obj = OverloadingSubclass2() + assert obj.VirtMethod[int](5) == 5 + + From 4020a0ca4738abdcb556c3d81f237081687b6461 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Tue, 17 Jan 2023 15:35:11 -0800 Subject: [PATCH 03/12] don't force setuptools upgrade during installation of requirements for testing upgrade caused InvalidVersion: Invalid version: '0.23ubuntu1' on Ubuntu due to setuptools dropping support for that version format --- .github/workflows/ARM.yml | 2 +- requirements.txt | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ARM.yml b/.github/workflows/ARM.yml index af257bcb8..0492b7a3a 100644 --- a/.github/workflows/ARM.yml +++ b/.github/workflows/ARM.yml @@ -27,7 +27,7 @@ jobs: - name: Install dependencies run: | - pip install --upgrade -r requirements.txt + pip install -r requirements.txt pip install pytest numpy # for tests - name: Build and Install diff --git a/requirements.txt b/requirements.txt index 8e911ef5a..33f38cca7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,8 +8,7 @@ codecov wheel pycparser -setuptools -clr-loader +clr-loader==0.2.* # Discover libpython -find_libpython \ No newline at end of file +find_libpython==0.3.* From a0418119b452e29a3e9f025fbed67fe19412fbee Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Wed, 18 Jan 2023 18:13:47 +0100 Subject: [PATCH 04/12] Ensure that `load` only runs once (#2079) Fixes #2078. --- CHANGELOG.md | 3 ++- pythonnet/__init__.py | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2347895a8..94a85e094 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Fixed -- Fixed error occuring when inheriting a class containing a virtual generic method. +- Fixed error occuring when inheriting a class containing a virtual generic method. +- Make a second call to `pythonnet.load` a no-op, as it was intended. ## [3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03 diff --git a/pythonnet/__init__.py b/pythonnet/__init__.py index 9d7b6c20a..5c1ca108a 100644 --- a/pythonnet/__init__.py +++ b/pythonnet/__init__.py @@ -120,7 +120,9 @@ def load(runtime: Union[clr_loader.Runtime, str, None] = None, **params: str) -> The same parameters as for `set_runtime` can be used. By default, `set_default_runtime` is called if no environment has been set yet and no - parameters are passed.""" + parameters are passed. + + After a successful call, further invocations will return immediately.""" global _LOADED, _LOADER_ASSEMBLY if _LOADED: @@ -142,6 +144,8 @@ def load(runtime: Union[clr_loader.Runtime, str, None] = None, **params: str) -> if func(b"") != 0: raise RuntimeError("Failed to initialize Python.Runtime.dll") + + _LOADED = True import atexit From c2fa4677035ef51d883be14aea9e41acfef281ea Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Sun, 29 Jan 2023 15:00:14 +0100 Subject: [PATCH 05/12] Remove suggestions to use `internal` functions (#2092) Fixes #2091 --- doc/source/dotnet.rst | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/doc/source/dotnet.rst b/doc/source/dotnet.rst index d02a6f0cb..03d729ee5 100644 --- a/doc/source/dotnet.rst +++ b/doc/source/dotnet.rst @@ -42,16 +42,10 @@ application. Before interacting with any of the objects or APIs provided by the ``Python.Runtime`` namespace, calling code must have acquired the Python -global interpreter lock by calling the ``PythonEngine.AcquireLock`` -method. The only exception to this rule is the -``PythonEngine.Initialize`` method, which may be called at startup -without having acquired the GIL. - -When finished using Python APIs, managed code must call a corresponding -``PythonEngine.ReleaseLock`` to release the GIL and allow other threads -to use Python. - -A ``using`` statement may be used to acquire and release the GIL: +global interpreter lock by ``using'' ``Py.GIL()``. The only exception to +this rule is the ``PythonEngine.Initialize`` method, which may be called +at startup without having acquired the GIL. The GIL is released again +by disposing the return value of `Py.GIL()`: .. code:: csharp @@ -59,11 +53,28 @@ A ``using`` statement may be used to acquire and release the GIL: { PythonEngine.Exec("doStuff()"); } + + // or + { + using var _ = Py.GIL() + PythonEngine.Exec("doStuff()"); + } + + // or + var gil = Py.GIL(); + try + { + PythonEngine.Exec("doStuff()"); + } + finally + { + gil.Dispose(); + } -The AcquireLock and ReleaseLock methods are thin wrappers over the -unmanaged ``PyGILState_Ensure`` and ``PyGILState_Release`` functions -from the Python API, and the documentation for those APIs applies to the -managed versions. +The ``Py.GIL()'' object is a thin wrapper over the unmanaged +``PyGILState_Ensure`` (on construction) and ``PyGILState_Release`` (on +disposal) functions from the Python API, and the documentation for those +APIs applies to the managed versions. Passing C# Objects to the Python Engine --------------------------------------- From a404d6e4d2ef6182763bd626ab08e0de4400e621 Mon Sep 17 00:00:00 2001 From: Rolf Madsen Date: Fri, 3 Feb 2023 23:59:20 +0100 Subject: [PATCH 06/12] 1783 Implement Interface And Inherit Class (#2028) * 1783 Implement Interface And Inherit Class Added support for multiple inheritance when inheriting from one base class and/or multiple interfaces. Added a unit test verifying that it works with a simple class and interface. This unit test would previously have failed since multiple types are in the class super class list. --- CHANGELOG.md | 2 + src/python_tests_runner/PythonTestRunner.cs | 1 + src/runtime/StateSerialization/MaybeType.cs | 4 +- src/runtime/TypeManager.cs | 17 ++-- src/runtime/Types/ClassDerived.cs | 10 ++- src/runtime/Types/MetaType.cs | 90 +++++++++++++++------ src/runtime/Types/ReflectedClrType.cs | 3 +- src/testing/classtest.cs | 12 +++ tests/test_subclass.py | 9 ++- 9 files changed, 105 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a85e094..818d90c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Fixed error occuring when inheriting a class containing a virtual generic method. - Make a second call to `pythonnet.load` a no-op, as it was intended. +- Added support for multiple inheritance when inheriting from a class and/or multiple interfaces. + ## [3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03 ### Added diff --git a/src/python_tests_runner/PythonTestRunner.cs b/src/python_tests_runner/PythonTestRunner.cs index 05298997b..f97cc5aec 100644 --- a/src/python_tests_runner/PythonTestRunner.cs +++ b/src/python_tests_runner/PythonTestRunner.cs @@ -35,6 +35,7 @@ static IEnumerable PythonTestCases() // Add the test that you want to debug here. yield return new[] { "test_indexer", "test_boolean_indexer" }; yield return new[] { "test_delegate", "test_bool_delegate" }; + yield return new[] { "test_subclass", "test_implement_interface_and_class" }; } /// diff --git a/src/runtime/StateSerialization/MaybeType.cs b/src/runtime/StateSerialization/MaybeType.cs index f3c96e369..884b7edb0 100644 --- a/src/runtime/StateSerialization/MaybeType.cs +++ b/src/runtime/StateSerialization/MaybeType.cs @@ -15,7 +15,7 @@ internal struct MaybeType : ISerializable const string SerializationName = "n"; readonly string name; readonly Type type; - + public string DeletedMessage { get @@ -61,4 +61,4 @@ public void GetObjectData(SerializationInfo serializationInfo, StreamingContext serializationInfo.AddValue(SerializationName, name); } } -} \ No newline at end of file +} diff --git a/src/runtime/TypeManager.cs b/src/runtime/TypeManager.cs index e0a78ba49..559d5148e 100644 --- a/src/runtime/TypeManager.cs +++ b/src/runtime/TypeManager.cs @@ -374,7 +374,7 @@ static PyTuple GetBaseTypeTuple(Type clrType) return new PyTuple(bases); } - internal static NewReference CreateSubType(BorrowedReference py_name, BorrowedReference py_base_type, BorrowedReference dictRef) + internal static NewReference CreateSubType(BorrowedReference py_name, ClassBase py_base_type, IList interfaces, BorrowedReference dictRef) { // Utility to create a subtype of a managed type with the ability for the // a python subtype able to override the managed implementation @@ -415,17 +415,10 @@ internal static NewReference CreateSubType(BorrowedReference py_name, BorrowedRe } // create the new managed type subclassing the base managed type - if (ManagedType.GetManagedObject(py_base_type) is ClassBase baseClass) - { - return ReflectedClrType.CreateSubclass(baseClass, name, - ns: (string?)namespaceStr, - assembly: (string?)assembly, - dict: dictRef); - } - else - { - return Exceptions.RaiseTypeError("invalid base class, expected CLR class type"); - } + return ReflectedClrType.CreateSubclass(py_base_type, interfaces, name, + ns: (string?)namespaceStr, + assembly: (string?)assembly, + dict: dictRef); } internal static IntPtr WriteMethodDef(IntPtr mdef, IntPtr name, IntPtr func, PyMethodFlags flags, IntPtr doc) diff --git a/src/runtime/Types/ClassDerived.cs b/src/runtime/Types/ClassDerived.cs index 61c602783..592eefd55 100644 --- a/src/runtime/Types/ClassDerived.cs +++ b/src/runtime/Types/ClassDerived.cs @@ -144,6 +144,7 @@ internal static NewReference ToPython(IPythonDerivedType obj) /// internal static Type CreateDerivedType(string name, Type baseType, + IList typeInterfaces, BorrowedReference py_dict, string? namespaceStr, string? assemblyName, @@ -163,7 +164,9 @@ internal static Type CreateDerivedType(string name, ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName); Type baseClass = baseType; - var interfaces = new List { typeof(IPythonDerivedType) }; + var interfaces = new HashSet { typeof(IPythonDerivedType) }; + foreach(var interfaceType in typeInterfaces) + interfaces.Add(interfaceType); // if the base type is an interface then use System.Object as the base class // and add the base type to the list of interfaces this new class will implement. @@ -214,8 +217,9 @@ internal static Type CreateDerivedType(string name, } } - // override any virtual methods not already overridden by the properties above - MethodInfo[] methods = baseType.GetMethods(); + // override any virtual not already overridden by the properties above + // also override any interface method. + var methods = baseType.GetMethods().Concat(interfaces.SelectMany(x => x.GetMethods())); var virtualMethods = new HashSet(); foreach (MethodInfo method in methods) { diff --git a/src/runtime/Types/MetaType.cs b/src/runtime/Types/MetaType.cs index 5b59f5139..57fcaa232 100644 --- a/src/runtime/Types/MetaType.cs +++ b/src/runtime/Types/MetaType.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -79,41 +82,80 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, BorrowedReference bases = Runtime.PyTuple_GetItem(args, 1); BorrowedReference dict = Runtime.PyTuple_GetItem(args, 2); - // We do not support multiple inheritance, so the bases argument - // should be a 1-item tuple containing the type we are subtyping. - // That type must itself have a managed implementation. We check - // that by making sure its metatype is the CLR metatype. + // Extract interface types and base class types. + var interfaces = new List(); - if (Runtime.PyTuple_Size(bases) != 1) - { - return Exceptions.RaiseTypeError("cannot use multiple inheritance with managed classes"); - } + // More than one base type case be declared, but an exception will be thrown + // if more than one is a class/not an interface. + var baseTypes = new List(); - BorrowedReference base_type = Runtime.PyTuple_GetItem(bases, 0); - BorrowedReference mt = Runtime.PyObject_TYPE(base_type); - - if (!(mt == PyCLRMetaType || mt == Runtime.PyTypeType)) + var baseClassCount = Runtime.PyTuple_Size(bases); + if (baseClassCount == 0) { - return Exceptions.RaiseTypeError("invalid metatype"); + return Exceptions.RaiseTypeError("zero base classes "); } - // Ensure that the reflected type is appropriate for subclassing, - // disallowing subclassing of delegates, enums and array types. - - if (GetManagedObject(base_type) is ClassBase cb) + for (nint i = 0; i < baseClassCount; i++) { - try + var baseTypeIt = Runtime.PyTuple_GetItem(bases, (int)i); + + if (GetManagedObject(baseTypeIt) is ClassBase classBaseIt) { - if (!cb.CanSubclass()) + if (!classBaseIt.type.Valid) + { + return Exceptions.RaiseTypeError("Invalid type used as a super type."); + } + if (classBaseIt.type.Value.IsInterface) { - return Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed"); + interfaces.Add(classBaseIt.type.Value); } + else + { + baseTypes.Add(classBaseIt); + } + } + else + { + return Exceptions.RaiseTypeError("Non .NET type used as super class for meta type. This is not supported."); } - catch (SerializationException) + } + // if the base type count is 0, there might still be interfaces to implement. + if (baseTypes.Count == 0) + { + baseTypes.Add(new ClassBase(typeof(object))); + } + + // Multiple inheritance is not supported, unless the other types are interfaces + if (baseTypes.Count > 1) + { + var types = string.Join(", ", baseTypes.Select(baseType => baseType.type.Value)); + return Exceptions.RaiseTypeError($"Multiple inheritance with managed classes cannot be used. Types: {types} "); + } + + // check if the list of interfaces contains no duplicates. + if (interfaces.Distinct().Count() != interfaces.Count) + { + // generate a string containing the problematic types. + var duplicateTypes = interfaces.GroupBy(type => type) + .Where(typeGroup => typeGroup.Count() > 1) + .Select(typeGroup => typeGroup.Key); + var duplicateTypesString = string.Join(", ", duplicateTypes); + + return Exceptions.RaiseTypeError($"An interface can only be implemented once. Duplicate types: {duplicateTypesString}"); + } + + var cb = baseTypes[0]; + try + { + if (!cb.CanSubclass()) { - return Exceptions.RaiseTypeError($"Underlying C# Base class {cb.type} has been deleted"); + return Exceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed"); } } + catch (SerializationException) + { + return Exceptions.RaiseTypeError($"Underlying C# Base class {cb.type} has been deleted"); + } BorrowedReference slots = Runtime.PyDict_GetItem(dict, PyIdentifier.__slots__); if (slots != null) @@ -130,10 +172,12 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args, using var clsDict = new PyDict(dict); if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { - return TypeManager.CreateSubType(name, base_type, clsDict); + return TypeManager.CreateSubType(name, baseTypes[0], interfaces, clsDict); } } + var base_type = Runtime.PyTuple_GetItem(bases, 0); + // otherwise just create a basic type without reflecting back into the managed side. IntPtr func = Util.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_new); NewReference type = NativeCall.Call_3(func, tp, args, kw); diff --git a/src/runtime/Types/ReflectedClrType.cs b/src/runtime/Types/ReflectedClrType.cs index d3d89bdb8..3d0aa7e99 100644 --- a/src/runtime/Types/ReflectedClrType.cs +++ b/src/runtime/Types/ReflectedClrType.cs @@ -68,7 +68,7 @@ internal void Restore(ClassBase cb) TypeManager.InitializeClass(this, cb, cb.type.Value); } - internal static NewReference CreateSubclass(ClassBase baseClass, + internal static NewReference CreateSubclass(ClassBase baseClass, IList interfaces, string name, string? assembly, string? ns, BorrowedReference dict) { @@ -76,6 +76,7 @@ internal static NewReference CreateSubclass(ClassBase baseClass, { Type subType = ClassDerivedObject.CreateDerivedType(name, baseClass.type.Value, + interfaces, dict, ns, assembly); diff --git a/src/testing/classtest.cs b/src/testing/classtest.cs index 68c0d8c55..993afdfc9 100644 --- a/src/testing/classtest.cs +++ b/src/testing/classtest.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; namespace Python.Test @@ -59,4 +60,15 @@ public ClassCtorTest2(string v) internal class InternalClass { } + + public class SimpleClass + { + public static void TestObject(object obj) + { + if ((!(obj is ISayHello1 && obj is SimpleClass))) + { + throw new Exception("Expected ISayHello and SimpleClass instance"); + } + } + } } diff --git a/tests/test_subclass.py b/tests/test_subclass.py index 504b82548..c6ab7650f 100644 --- a/tests/test_subclass.py +++ b/tests/test_subclass.py @@ -9,7 +9,7 @@ import System import pytest from Python.Test import (IInterfaceTest, SubClassTest, EventArgsTest, - FunctionsTest, IGenericInterface, GenericVirtualMethodTest) + FunctionsTest, IGenericInterface, GenericVirtualMethodTest, SimpleClass, ISayHello1) from System.Collections.Generic import List @@ -338,4 +338,9 @@ class OverloadingSubclass2(OverloadingSubclass): obj = OverloadingSubclass2() assert obj.VirtMethod[int](5) == 5 - +def test_implement_interface_and_class(): + class DualSubClass0(ISayHello1, SimpleClass): + __namespace__ = "Test" + def SayHello(self): + return "hello" + obj = DualSubClass0() From 131b466dcaa9cf9135f3b1859c8a41ee229cace8 Mon Sep 17 00:00:00 2001 From: legomanww Date: Sun, 12 Mar 2023 14:01:52 -0700 Subject: [PATCH 07/12] Fix `GetBuffer` throwing `ArgumentOutOfRangeException` (#2120) * fix: incorrect length for buffer copy * test: add PyBuffer test for strides * docs: update `CHANGELOG` and `AUTHORS` --- AUTHORS.md | 1 + CHANGELOG.md | 1 + src/embed_tests/TestPyBuffer.cs | 36 +++++++++++++++++++++++++++++ src/runtime/PythonTypes/PyBuffer.cs | 8 +++---- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 92f1a4a97..577e898aa 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -85,3 +85,4 @@ - ([@alxnull](https://github.com/alxnull)) - ([@gpetrou](https://github.com/gpetrou)) - Ehsan Iran-Nejad ([@eirannejad](https://github.com/eirannejad)) +- ([@legomanww](https://github.com/legomanww)) diff --git a/CHANGELOG.md b/CHANGELOG.md index 818d90c52..b5a46ce04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Make a second call to `pythonnet.load` a no-op, as it was intended. - Added support for multiple inheritance when inheriting from a class and/or multiple interfaces. +- Fixed error occuring when calling `GetBuffer` for anything other than `PyBUF.SIMPLE` ## [3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03 diff --git a/src/embed_tests/TestPyBuffer.cs b/src/embed_tests/TestPyBuffer.cs index a1bcc161d..1b4e28d12 100644 --- a/src/embed_tests/TestPyBuffer.cs +++ b/src/embed_tests/TestPyBuffer.cs @@ -110,6 +110,26 @@ public void Finalization() Assert.AreEqual(1, arr.Refcount); } + [Test] + public void MultidimensionalNumPyArray() + { + var ndarray = np.arange(24).reshape(1,2,3,4).T; + PyObject ndim = ndarray.ndim; + PyObject shape = ndarray.shape; + PyObject strides = ndarray.strides; + PyObject contiguous = ndarray.flags["C_CONTIGUOUS"]; + + using PyBuffer buf = ndarray.GetBuffer(PyBUF.STRIDED); + + Assert.Multiple(() => + { + Assert.That(buf.Dimensions, Is.EqualTo(ndim.As())); + Assert.That(buf.Shape, Is.EqualTo(shape.As())); + Assert.That(buf.Strides, Is.EqualTo(strides.As())); + Assert.That(buf.IsContiguous(BufferOrderStyle.C), Is.EqualTo(contiguous.As())); + }); + } + [MethodImpl(MethodImplOptions.NoInlining)] static void MakeBufAndLeak(PyObject bufProvider) { @@ -121,5 +141,21 @@ static PyObject ByteArrayFromAsciiString(string str) using var scope = Py.CreateScope(); return Runtime.Runtime.PyByteArray_FromStringAndSize(str).MoveToPyObject(); } + + dynamic np + { + get + { + try + { + return Py.Import("numpy"); + } + catch (PythonException) + { + Assert.Inconclusive("Numpy or dependency not installed"); + return null; + } + } + } } } diff --git a/src/runtime/PythonTypes/PyBuffer.cs b/src/runtime/PythonTypes/PyBuffer.cs index de0e7122f..120582494 100644 --- a/src/runtime/PythonTypes/PyBuffer.cs +++ b/src/runtime/PythonTypes/PyBuffer.cs @@ -11,7 +11,7 @@ public sealed class PyBuffer : IDisposable private PyObject _exporter; private Py_buffer _view; - unsafe internal PyBuffer(PyObject exporter, PyBUF flags) + internal PyBuffer(PyObject exporter, PyBUF flags) { _view = new Py_buffer(); @@ -25,17 +25,17 @@ unsafe internal PyBuffer(PyObject exporter, PyBUF flags) var intPtrBuf = new IntPtr[_view.ndim]; if (_view.shape != IntPtr.Zero) { - Marshal.Copy(_view.shape, intPtrBuf, 0, (int)_view.len * sizeof(IntPtr)); + Marshal.Copy(_view.shape, intPtrBuf, 0, _view.ndim); Shape = intPtrBuf.Select(x => (long)x).ToArray(); } if (_view.strides != IntPtr.Zero) { - Marshal.Copy(_view.strides, intPtrBuf, 0, (int)_view.len * sizeof(IntPtr)); + Marshal.Copy(_view.strides, intPtrBuf, 0, _view.ndim); Strides = intPtrBuf.Select(x => (long)x).ToArray(); } if (_view.suboffsets != IntPtr.Zero) { - Marshal.Copy(_view.suboffsets, intPtrBuf, 0, (int)_view.len * sizeof(IntPtr)); + Marshal.Copy(_view.suboffsets, intPtrBuf, 0, _view.ndim); SubOffsets = intPtrBuf.Select(x => (long)x).ToArray(); } } From a1cd73fa5bd93962737449feea3bd425f37c42ba Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 4 May 2023 08:29:39 +0200 Subject: [PATCH 08/12] Exclude .gitignore from binary distribution --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 52f1adb18..98a3b26fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ file = "version.txt" [tool.setuptools.packages.find] include = ["pythonnet*"] +exclude = [".gitignore"] [tool.pytest.ini_options] xfail_strict = true From dddadbe78ef0fba3e8ffde30c466f224dbbc9aea Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Fri, 7 Jul 2023 17:39:37 +0200 Subject: [PATCH 09/12] Adjust docs for importing --- doc/source/dotnet.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/dotnet.rst b/doc/source/dotnet.rst index 03d729ee5..43b7659ac 100644 --- a/doc/source/dotnet.rst +++ b/doc/source/dotnet.rst @@ -17,7 +17,7 @@ to: - Reference ``Python.Runtime.dll`` (e.g. via a ``PackageReference``) - Call ``PythonEngine.Initialize()`` to initialize Python -- Call ``PythonEngine.ImportModule(name)`` to import a module +- Call ``var mod = PyModule.Import(name)`` to import a module as ``mod`` The module you import can either start working with your managed app environment at the time its imported, or you can explicitly lookup and From 3b6500fbdc844096665a24ba07f5a56c11192e1b Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Fri, 21 Jul 2023 08:47:21 +0200 Subject: [PATCH 10/12] Add documentation dependency to fix empty docs --- doc/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/requirements.txt b/doc/requirements.txt index 64018840c..8ef3b7159 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -7,3 +7,6 @@ pygments>=2.7 # C# via doxygen breathe git+https://github.com/rogerbarton/sphinx-csharp.git + +# Dependency of pythonnet, needed for autodocs +clr_loader From 639023a5ca0a3375fd39d2fea8baa5e9888284d0 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 29 Aug 2023 17:18:19 +0200 Subject: [PATCH 11/12] Bump clr_loader dependency --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 98a3b26fd..bf488bb92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ license = {text = "MIT"} readme = "README.rst" dependencies = [ - "clr_loader>=0.2.2,<0.3.0" + "clr_loader>=0.2.6,<0.3.0" ] requires-python = ">=3.7, <3.12" From 6a4e04c1983b24888a1e8b04d75c28086594cb63 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 29 Aug 2023 17:22:48 +0200 Subject: [PATCH 12/12] Release 3.0.2 --- CHANGELOG.md | 12 ++++++++---- version.txt | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a46ce04..4ba0b935c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,15 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Fixed -- Fixed error occuring when inheriting a class containing a virtual generic method. -- Make a second call to `pythonnet.load` a no-op, as it was intended. +## [3.0.2](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.2) - 2023-08-29 -- Added support for multiple inheritance when inheriting from a class and/or multiple interfaces. -- Fixed error occuring when calling `GetBuffer` for anything other than `PyBUF.SIMPLE` +### Fixed + +- Fixed error occuring when inheriting a class containing a virtual generic method +- Make a second call to `pythonnet.load` a no-op, as it was intended +- Added support for multiple inheritance when inheriting from a class and/or multiple interfaces +- Fixed error occuring when calling `GetBuffer` for anything other than `PyBUF.SIMPLE` +- Bumped `clr_loader` dependency to incorporate patches ## [3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03 diff --git a/version.txt b/version.txt index 0f9d6b15d..b50214693 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.1.0-dev +3.0.2 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy