From 5cb300a7a83d2599ad1af921641a494324ed04c0 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Sat, 23 May 2020 19:05:40 -0700 Subject: [PATCH 1/8] added a few mixins to reflected .NET collection types, that implement corresponding pythonic interfaces --- src/runtime/InteropConfiguration.cs | 3 + .../Mixins/CollectionMixinsProvider.cs | 90 +++++++++++++++++++ src/runtime/Mixins/collections.py | 61 +++++++++++++ src/runtime/Python.Runtime.csproj | 2 +- src/runtime/Util.cs | 3 + src/runtime/pyscope.cs | 2 +- src/runtime/pythonengine.cs | 36 +++++++- src/runtime/runtime.cs | 3 +- 8 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 src/runtime/Mixins/CollectionMixinsProvider.cs create mode 100644 src/runtime/Mixins/collections.py diff --git a/src/runtime/InteropConfiguration.cs b/src/runtime/InteropConfiguration.cs index 6853115fe..78af5037a 100644 --- a/src/runtime/InteropConfiguration.cs +++ b/src/runtime/InteropConfiguration.cs @@ -3,6 +3,8 @@ namespace Python.Runtime using System; using System.Collections.Generic; + using Python.Runtime.Mixins; + public sealed class InteropConfiguration { internal readonly PythonBaseTypeProviderGroup pythonBaseTypeProviders @@ -18,6 +20,7 @@ public static InteropConfiguration MakeDefault() PythonBaseTypeProviders = { DefaultBaseTypeProvider.Instance, + new CollectionMixinsProvider(new Lazy(() => Py.Import("clr._extras.collections"))), }, }; } diff --git a/src/runtime/Mixins/CollectionMixinsProvider.cs b/src/runtime/Mixins/CollectionMixinsProvider.cs new file mode 100644 index 000000000..48ea35f1c --- /dev/null +++ b/src/runtime/Mixins/CollectionMixinsProvider.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Python.Runtime.Mixins +{ + class CollectionMixinsProvider : IPythonBaseTypeProvider + { + readonly Lazy mixinsModule; + public CollectionMixinsProvider(Lazy mixinsModule) + { + this.mixinsModule = mixinsModule ?? throw new ArgumentNullException(nameof(mixinsModule)); + } + + public PyObject Mixins => this.mixinsModule.Value; + + public IEnumerable GetBaseTypes(Type type, IList existingBases) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + + if (existingBases is null) + throw new ArgumentNullException(nameof(existingBases)); + + var interfaces = NewInterfaces(type).Select(GetDefinition).ToArray(); + + var newBases = new List(); + newBases.AddRange(existingBases); + + // dictionaries + if (interfaces.Contains(typeof(IDictionary<,>))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("MutableMappingMixin"))); + } + else if (interfaces.Contains(typeof(IReadOnlyDictionary<,>))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("MappingMixin"))); + } + + // item collections + if (interfaces.Contains(typeof(IList<>)) + || interfaces.Contains(typeof(System.Collections.IList))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("MutableSequenceMixin"))); + } + else if (interfaces.Contains(typeof(IReadOnlyList<>))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("SequenceMixin"))); + } + else if (interfaces.Contains(typeof(ICollection<>)) + || interfaces.Contains(typeof(System.Collections.ICollection))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("CollectionMixin"))); + } + else if (interfaces.Contains(typeof(System.Collections.IEnumerable))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("IterableMixin"))); + } + + // enumerators + if (interfaces.Contains(typeof(System.Collections.IEnumerator))) + { + newBases.Add(new PyType(this.Mixins.GetAttr("IteratorMixin"))); + } + + if (newBases.Count == existingBases.Count) + { + return existingBases; + } + + if (type.IsInterface && type.BaseType is null) + { + newBases.RemoveAll(@base => @base.Handle == Runtime.PyBaseObjectType); + } + + return newBases; + } + + static Type[] NewInterfaces(Type type) + { + var result = type.GetInterfaces(); + return type.BaseType != null + ? result.Except(type.BaseType.GetInterfaces()).ToArray() + : result; + } + + static Type GetDefinition(Type type) + => type.IsGenericType ? type.GetGenericTypeDefinition() : type; + } +} diff --git a/src/runtime/Mixins/collections.py b/src/runtime/Mixins/collections.py new file mode 100644 index 000000000..d38738295 --- /dev/null +++ b/src/runtime/Mixins/collections.py @@ -0,0 +1,61 @@ +""" +Implements collections.abc for common .NET types +https://docs.python.org/3.6/library/collections.abc.html +""" + +import collections.abc as col + +class IteratorMixin(col.Iterator): + def close(self): + self.Dispose() + +class IterableMixin(col.Iterable): + pass + +class SizedMixin(col.Sized): + def __len__(self): return self.Count + +class ContainerMixin(col.Container): + def __contains__(self, item): return self.Contains(item) + +try: + abc_Collection = col.Collection +except AttributeError: + # Python 3.5- does not have collections.abc.Collection + abc_Collection = col.Container + +class CollectionMixin(SizedMixin, IterableMixin, ContainerMixin, abc_Collection): + pass + +class SequenceMixin(CollectionMixin, col.Sequence): + pass + +class MutableSequenceMixin(SequenceMixin, col.MutableSequence): + pass + +class MappingMixin(CollectionMixin, col.Mapping): + def keys(self): return self.Keys + def items(self): return self + def values(self): return self.Values + def __iter__(self): raise NotImplementedError + def get(self, key): + _, item = self.TryGetValue(key) + return item + +class MutableMappingMixin(MappingMixin, col.MutableMapping): + def __delitem__(self, key): + return self.Remove(key) + def clear(self): + self.Clear() + def pop(self, key): + return self.Remove(key) + def setdefault(self, key, value): + existed, item = self.TryGetValue(key) + if existed: + return item + else: + self[key] = value + return value + def update(self, items): + for key, value in items: + self[key] = value diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index 0311dbf9a..37502096c 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -39,10 +39,10 @@ - clr.py + diff --git a/src/runtime/Util.cs b/src/runtime/Util.cs index c70f5cf51..9c3aa9802 100644 --- a/src/runtime/Util.cs +++ b/src/runtime/Util.cs @@ -10,6 +10,9 @@ internal static class Util internal const string MinimalPythonVersionRequired = "Only Python 3.5 or newer is supported"; + internal const string UseOverloadWithReferenceTypes = + "This API is unsafe, and will be removed in the future. Use overloads working with *Reference types"; + internal static Int64 ReadCLong(IntPtr tp, int offset) { // On Windows, a C long is always 32 bits. diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs index 8cb40d781..315eb75e5 100644 --- a/src/runtime/pyscope.cs +++ b/src/runtime/pyscope.cs @@ -66,7 +66,7 @@ private PyScope(IntPtr ptr, PyScopeManager manager) : base(ptr) PythonException.ThrowIfIsNull(variables); int res = Runtime.PyDict_SetItem( - VarsRef, PyIdentifier.__builtins__, + VarsRef, new BorrowedReference(PyIdentifier.__builtins__), Runtime.PyEval_GetBuiltins() ); PythonException.ThrowIfIsNotZero(res); diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index cd608fe93..8cdb235e9 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -223,10 +223,8 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, var locals = new PyDict(); try { - BorrowedReference module = Runtime.PyImport_AddModule("clr._extras"); + BorrowedReference module = DefineModule("clr._extras"); BorrowedReference module_globals = Runtime.PyModule_GetDict(module); - BorrowedReference builtins = Runtime.PyEval_GetBuiltins(); - Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); Assembly assembly = Assembly.GetExecutingAssembly(); using (Stream stream = assembly.GetManifestResourceStream("clr.py")) @@ -237,6 +235,8 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, Exec(clr_py, module_globals, locals.Reference); } + LoadExtraModules(module_globals); + // add the imported module to the clr module, and copy the API functions // and decorators into the main clr module. Runtime.PyDict_SetItemString(clr_dict, "_extras", module); @@ -258,6 +258,34 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, } } + static BorrowedReference DefineModule(string name) + { + var module = Runtime.PyImport_AddModule(name); + var module_globals = Runtime.PyModule_GetDict(module); + var builtins = Runtime.PyEval_GetBuiltins(); + Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); + return module; + } + + static void LoadExtraModules(BorrowedReference targetModuleDict) + { + Assembly assembly = Assembly.GetExecutingAssembly(); + foreach (string nested in new[] { "collections" }) + { + var module = DefineModule("clr._extras." + nested); + var module_globals = Runtime.PyModule_GetDict(module); + string resourceName = typeof(PythonEngine).Namespace + ".Mixins." + nested + ".py"; + using (var stream = assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { + string pyCode = reader.ReadToEnd(); + Exec(pyCode, module_globals.DangerousGetAddress(), module_globals.DangerousGetAddress()); + } + + Runtime.PyDict_SetItemString(targetModuleDict, nested, module); + } + } + static void OnDomainUnload(object _, EventArgs __) { Shutdown(); @@ -618,7 +646,7 @@ internal static PyObject RunString(string code, BorrowedReference globals, Borro { globals = tempGlobals = NewReference.DangerousFromPointer(Runtime.PyDict_New()); Runtime.PyDict_SetItem( - globals, PyIdentifier.__builtins__, + globals, new BorrowedReference(PyIdentifier.__builtins__), Runtime.PyEval_GetBuiltins() ); } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 4114fc4d0..e1f79eb95 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1679,6 +1679,7 @@ internal static BorrowedReference PyDict_GetItemString(BorrowedReference pointer /// /// Return 0 on success or -1 on failure. /// + [Obsolete] internal static int PyDict_SetItem(BorrowedReference dict, IntPtr key, BorrowedReference value) => Delegates.PyDict_SetItem(dict, new BorrowedReference(key), value); /// /// Return 0 on success or -1 on failure. @@ -2038,7 +2039,7 @@ internal static bool PyType_IsSameAsOrSubtype(BorrowedReference type, BorrowedRe internal static NewReference PyType_FromSpecWithBases(in NativeTypeSpec spec, BorrowedReference bases) => Delegates.PyType_FromSpecWithBases(in spec, bases); /// - /// Finalize a type object. This should be called on all type objects to finish their initialization. This function is responsible for adding inherited slots from a type’s base class. Return 0 on success, or return -1 and sets an exception on error. + /// Finalize a type object. This should be called on all type objects to finish their initialization. This function is responsible for adding inherited slots from a type�s base class. Return 0 on success, or return -1 and sets an exception on error. /// internal static int PyType_Ready(IntPtr type) => Delegates.PyType_Ready(type); From cd044c8a0955b811583d98ce95d8bbfbe2c87027 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Wed, 3 Jun 2020 00:02:52 -0700 Subject: [PATCH 2/8] fixed MappingMixin implementation (untested) --- src/runtime/Mixins/collections.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/Mixins/collections.py b/src/runtime/Mixins/collections.py index d38738295..f9299f951 100644 --- a/src/runtime/Mixins/collections.py +++ b/src/runtime/Mixins/collections.py @@ -34,10 +34,11 @@ class MutableSequenceMixin(SequenceMixin, col.MutableSequence): pass class MappingMixin(CollectionMixin, col.Mapping): + def __contains__(self, item): return self.ContainsKey(item) def keys(self): return self.Keys - def items(self): return self + def items(self): return [(k,self[k]) for k in self.Keys] def values(self): return self.Values - def __iter__(self): raise NotImplementedError + def __iter__(self): return self.Keys.__iter__() def get(self, key): _, item = self.TryGetValue(key) return item From 85897e340c3c661f8d310d2ae2b141eb9590e3ed Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Tue, 16 Jun 2020 19:12:56 -0700 Subject: [PATCH 3/8] fixed implementation of mixins for Mapping and MutableMapping (still untested) --- src/runtime/Mixins/collections.py | 38 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/runtime/Mixins/collections.py b/src/runtime/Mixins/collections.py index f9299f951..e89db6208 100644 --- a/src/runtime/Mixins/collections.py +++ b/src/runtime/Mixins/collections.py @@ -39,24 +39,44 @@ def keys(self): return self.Keys def items(self): return [(k,self[k]) for k in self.Keys] def values(self): return self.Values def __iter__(self): return self.Keys.__iter__() - def get(self, key): - _, item = self.TryGetValue(key) - return item + def get(self, key, default=None): + existed, item = self.TryGetValue(key) + return item if existed else default class MutableMappingMixin(MappingMixin, col.MutableMapping): + _UNSET_ = object() + def __delitem__(self, key): - return self.Remove(key) + self.Remove(key) + def clear(self): self.Clear() - def pop(self, key): - return self.Remove(key) - def setdefault(self, key, value): + + def pop(self, key, default=_UNSET_): + existed, item = self.TryGetValue(key) + if existed: + self.Remove(key) + return item + elif default == self._UNSET_: + raise KeyError(key) + else: + return default + + def setdefault(self, key, value=None): existed, item = self.TryGetValue(key) if existed: return item else: self[key] = value return value - def update(self, items): - for key, value in items: + + def update(self, items, **kwargs): + if isinstance(items, col.Mapping): + for key, value in items.items(): + self[key] = value + else: + for key, value in items: + self[key] = value + + for key, value in kwargs.items(): self[key] = value From 38ac73b9e883b3f00fb7b51d20e8931566f00071 Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Tue, 16 Jun 2020 23:25:37 -0700 Subject: [PATCH 4/8] fixed mixin calls to TryGetValue --- src/runtime/Mixins/collections.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime/Mixins/collections.py b/src/runtime/Mixins/collections.py index e89db6208..a82032472 100644 --- a/src/runtime/Mixins/collections.py +++ b/src/runtime/Mixins/collections.py @@ -36,11 +36,11 @@ class MutableSequenceMixin(SequenceMixin, col.MutableSequence): class MappingMixin(CollectionMixin, col.Mapping): def __contains__(self, item): return self.ContainsKey(item) def keys(self): return self.Keys - def items(self): return [(k,self[k]) for k in self.Keys] + def items(self): return [(k,self.get(k)) for k in self.Keys] def values(self): return self.Values def __iter__(self): return self.Keys.__iter__() def get(self, key, default=None): - existed, item = self.TryGetValue(key) + existed, item = self.TryGetValue(key, None) return item if existed else default class MutableMappingMixin(MappingMixin, col.MutableMapping): @@ -53,7 +53,7 @@ def clear(self): self.Clear() def pop(self, key, default=_UNSET_): - existed, item = self.TryGetValue(key) + existed, item = self.TryGetValue(key, None) if existed: self.Remove(key) return item @@ -63,7 +63,7 @@ def pop(self, key, default=_UNSET_): return default def setdefault(self, key, value=None): - existed, item = self.TryGetValue(key) + existed, item = self.TryGetValue(key, None) if existed: return item else: From b77b7ceb74d9e972621d637420a0a2195b36ed49 Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Sun, 5 Sep 2021 09:13:05 -0700 Subject: [PATCH 5/8] added a few tests for collection mixins --- tests/test_collection_mixins.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/test_collection_mixins.py diff --git a/tests/test_collection_mixins.py b/tests/test_collection_mixins.py new file mode 100644 index 000000000..2f74e93ab --- /dev/null +++ b/tests/test_collection_mixins.py @@ -0,0 +1,16 @@ +import System.Collections.Generic as C + +def test_contains(): + l = C.List[int]() + l.Add(42) + assert 42 in l + assert 43 not in l + +def test_dict_items(): + d = C.Dictionary[int, str]() + d[42] = "a" + items = d.items() + assert len(items) == 1 + k,v = items[0] + assert k == 42 + assert v == "a" From a38849ea9f9b0b04c6fc3d215440ada0a222215e Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Sun, 5 Sep 2021 09:16:36 -0700 Subject: [PATCH 6/8] mentioned collection mixins in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce9102a5d..c769796f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. - Improved exception handling: - exceptions can now be converted with codecs - `InnerException` and `__cause__` are propagated properly +- .NET collection types now implement standard Python collection interfaces from `collections.abc`. +See [Mixins/collections.py](src/runtime/Mixins/collections.py). - .NET arrays implement Python buffer protocol From 6b20409df7b5d5787d165c587d91b7f37a815b1f Mon Sep 17 00:00:00 2001 From: Victor Milovanov Date: Thu, 28 May 2020 17:20:54 -0700 Subject: [PATCH 7/8] refactored LoadExtraModules for Mixins into LoadSubmodule + LoadMixins --- src/runtime/Util.cs | 12 ++++++++++++ src/runtime/pythonengine.cs | 37 +++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/runtime/Util.cs b/src/runtime/Util.cs index 9c3aa9802..36ce6d676 100644 --- a/src/runtime/Util.cs +++ b/src/runtime/Util.cs @@ -44,5 +44,17 @@ internal static void WriteCLong(IntPtr type, int offset, Int64 flags) /// internal static IntPtr Coalesce(this IntPtr primary, IntPtr fallback) => primary == IntPtr.Zero ? fallback : primary; + + /// + /// Gets substring after last occurrence of + /// + internal static string AfterLast(this string str, char symbol) + { + if (str is null) + throw new ArgumentNullException(nameof(str)); + + int last = str.LastIndexOf(symbol); + return last >= 0 ? str.Substring(last + 1) : null; + } } } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 8cdb235e9..782023746 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -235,7 +236,7 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, Exec(clr_py, module_globals, locals.Reference); } - LoadExtraModules(module_globals); + LoadMixins(module_globals); // add the imported module to the clr module, and copy the API functions // and decorators into the main clr module. @@ -267,23 +268,31 @@ static BorrowedReference DefineModule(string name) return module; } - static void LoadExtraModules(BorrowedReference targetModuleDict) + static void LoadMixins(BorrowedReference targetModuleDict) { - Assembly assembly = Assembly.GetExecutingAssembly(); - foreach (string nested in new[] { "collections" }) + foreach (string nested in new[] {"collections"}) { - var module = DefineModule("clr._extras." + nested); - var module_globals = Runtime.PyModule_GetDict(module); - string resourceName = typeof(PythonEngine).Namespace + ".Mixins." + nested + ".py"; - using (var stream = assembly.GetManifestResourceStream(resourceName)) - using (var reader = new StreamReader(stream)) - { - string pyCode = reader.ReadToEnd(); - Exec(pyCode, module_globals.DangerousGetAddress(), module_globals.DangerousGetAddress()); - } + LoadSubmodule(targetModuleDict, + fullName: "clr._extras." + nested, + resourceName: typeof(PythonEngine).Namespace + ".Mixins." + nested + ".py"); + } + } - Runtime.PyDict_SetItemString(targetModuleDict, nested, module); + static void LoadSubmodule(BorrowedReference targetModuleDict, string fullName, string resourceName) + { + string memberName = fullName.AfterLast('.'); + Debug.Assert(memberName != null); + Assembly assembly = Assembly.GetExecutingAssembly(); + var module = DefineModule(fullName); + var module_globals = Runtime.PyModule_GetDict(module); + using (var stream = assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { + string pyCode = reader.ReadToEnd(); + Exec(pyCode, module_globals.DangerousGetAddress(), module_globals.DangerousGetAddress()); } + + Runtime.PyDict_SetItemString(targetModuleDict, memberName, module); } static void OnDomainUnload(object _, EventArgs __) From 197689e07e5ce69dd73122371306cf4d69eb16ec Mon Sep 17 00:00:00 2001 From: Victor Nova Date: Wed, 22 Sep 2021 12:19:57 -0700 Subject: [PATCH 8/8] added a workaround for tp_clear implementations, that do not check, that they are not the first in tp_clear's MRO https://bugs.python.org/issue45266 --- src/runtime/classbase.cs | 28 +++++++++++++++++++++++++--- src/runtime/clrobject.cs | 2 +- src/runtime/managedtype.cs | 4 +++- src/runtime/pytype.cs | 6 ++++++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index fed172e49..dd89358eb 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -360,18 +360,40 @@ public static void tp_dealloc(IntPtr ob) public static int tp_clear(IntPtr ob) { - ManagedType self = GetManagedObject(ob); + if (GetManagedObject(ob) is { } self) + { + if (self.clearReentryGuard) return 0; + + // workaround for https://bugs.python.org/issue45266 + self.clearReentryGuard = true; + + try + { + return ClearImpl(ob, self); + } + finally + { + self.clearReentryGuard = false; + } + } + else + { + return ClearImpl(ob, null); + } + } + static int ClearImpl(IntPtr ob, ManagedType self) + { bool isTypeObject = Runtime.PyObject_TYPE(ob) == Runtime.PyCLRMetaType; if (!isTypeObject) { - ClearObjectDict(ob); - int baseClearResult = BaseUnmanagedClear(ob); if (baseClearResult != 0) { return baseClearResult; } + + ClearObjectDict(ob); } if (self is not null) self.tpHandle = IntPtr.Zero; return 0; diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs index 07b816e05..114cce070 100644 --- a/src/runtime/clrobject.cs +++ b/src/runtime/clrobject.cs @@ -12,7 +12,7 @@ internal class CLRObject : ManagedType internal CLRObject(object ob, IntPtr tp) { - System.Diagnostics.Debug.Assert(tp != IntPtr.Zero); + Debug.Assert(tp != IntPtr.Zero); IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); tpHandle = tp; diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index c22b479ac..9c0c54e96 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -28,6 +28,8 @@ internal enum TrackTypes internal IntPtr pyHandle; // PyObject * internal IntPtr tpHandle; // PyType * + internal bool clearReentryGuard; + internal BorrowedReference ObjectReference => new(pyHandle); internal BorrowedReference TypeReference => new(tpHandle); @@ -145,7 +147,7 @@ internal static bool IsInstanceOfManagedType(IntPtr ob) internal static bool IsManagedType(BorrowedReference type) { - var flags = (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags); + var flags = PyType.GetFlags(type); return (flags & TypeFlags.HasClrInstance) != 0; } diff --git a/src/runtime/pytype.cs b/src/runtime/pytype.cs index 78cfad3f2..b144d09c3 100644 --- a/src/runtime/pytype.cs +++ b/src/runtime/pytype.cs @@ -103,6 +103,12 @@ internal IntPtr GetSlot(TypeSlotID slot) return Exceptions.ErrorCheckIfNull(result); } + internal static TypeFlags GetFlags(BorrowedReference type) + { + Debug.Assert(TypeOffset.tp_flags > 0); + return (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags); + } + internal static BorrowedReference GetBase(BorrowedReference type) { Debug.Assert(IsType(type)); 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